/* ---- This file is part of SECONDO. Copyright (C) 2004, University in Hagen, Department of Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- //[_] [\_] //characters [1] verbatim: [$] [$] //characters [2] formula: [$] [$] //characters [3] capital: [\textsc{] [}] //characters [4] teletype: [\texttt{] [}] 1 Headerfile "PictureFuns.h"[4] January-May 2008, Mirko Dibbert 1.1 Overview This headerfile contains the "PictureFuns"[4] class, which implements all functions for the "DistDataReg"[4], "DistfunReg"[4], "HPointReg"[4] and "HRectReg"[4] classes for the picture type constructor. 1.2 Includes and defines */ #ifndef __PICTURE_FUNCTIONS_H__ #define __PICTURE_FUNCTIONS_H__ #include "DistfunReg.h" #include "HPointReg.h" #include "Algebras/Picture/PictureAlgebra.h" #include "Algebras/Picture/JPEGPicture.h" #include namespace gta { enum SIM_MATRIX_ID { SIM_MATRIX_NONE, SIM_MATRIX_HSV64, SIM_MATRIX_HSV128, SIM_MATRIX_HSV256, SIM_MATRIX_LAB256 }; const std::string HSV8("hsv8"); const std::string HSV16("hsv16"); const std::string HSV32("hsv32"); const std::string HSV64("hsv64"); const std::string HSV128("hsv128"); const std::string HSV256("hsv256"); const std::string LAB256("lab256"); const std::string HSV8_NCOMPR("hsv8_ncompr"); const std::string HSV16_NCOMPR("hsv16_ncompr"); const std::string HSV32_NCOMPR("hsv32_ncompr"); const std::string HSV64_NCOMPR("hsv64_ncompr"); const std::string HSV128_NCOMPR("hsv128_ncompr"); const std::string HSV256_NCOMPR("hsv256_ncompr"); const std::string LAB256_NCOMPR("lab256_ncompr"); const std::string HSV8_DESCR("hsv-color histogram with 8 bins"); const std::string HSV16_DESCR("hsv-color histogram with 16 bins"); const std::string HSV32_DESCR("hsv-color histogram with 32 bins"); const std::string HSV64_DESCR("hsv-color histogram with 64 bins"); const std::string HSV128_DESCR("hsv-color histogram with 128 bins"); const std::string HSV256_DESCR("hsv-color histogram with 256 bins"); const std::string LAB256_DESCR("lab-color histogram with 256 bins"); const std::string HSV8_NCOMPR_DESCR( "uncompressed hsv-color histogram with 8 bins"); const std::string HSV16_NCOMPR_DESCR( "uncompressed hsv-color histogram with 16 bins"); const std::string HSV32_NCOMPR_DESCR( "uncompressed hsv-color histogram with 32 bins"); const std::string HSV64_NCOMPR_DESCR( "uncompressed hsv-color histogram with 64 bins"); const std::string HSV128_NCOMPR_DESCR( "uncompressed hsv-color histogram with 128 bins"); const std::string HSV256_NCOMPR_DESCR( "uncompressed hsv-color histogram with 256 bins"); const std::string LAB256_NCOMPR_DESCR( "uncompressed lab-color histogram with 256 bins"); // domain of the histogram values (should be some floating point // value, e.g. double or float) typedef float histDomain; /******************************************************************** 1.1 Struct Lab This struct models a lab-color value, which will be computed in the constructor from a rgb-color value. ********************************************************************/ struct Lab { signed char L, a, b; Lab (unsigned char r_, unsigned char g_, unsigned char b_); }; // struct Lab /******************************************************************** 1.1 Struct HSV This struct models a hsv-color value, which will be computed in the constructor from a rgb-color value. ********************************************************************/ struct HSV { int h, s, v; HSV (unsigned char r, unsigned char g, unsigned char b); }; // struct HSV /******************************************************************** 1.1 Class PictureFuns ********************************************************************/ class PictureFuns { public: /* The following methods are called from the "initialize"[4] method of the "DistDataReg"[4], "DistfunReg"[4], "HPoint Reg"[4] and "HRectReg"[4] classes. */ static void initDistData(); static void initDistfuns(); static void initHPointReg(); /******************************************************************** getdata functions for the avaliable distdata types: ********************************************************************/ template static DistData* getData_hsv8(const void* attr); template static DistData* getData_hsv16(const void* attr); template static DistData* getData_hsv32(const void* attr); template static DistData* getData_hsv64(const void* attr); template static DistData* getData_hsv128(const void* attr); template static DistData* getData_hsv256(const void* attr); template static DistData* getData_lab256(const void* attr); /******************************************************************** gethpoint functions: ********************************************************************/ static HPoint* getHPoint_hsv8(const void* attr); static HPoint* getHPoint_hsv16(const void* attr); static HPoint* getHPoint_hsv32(const void* attr); static HPoint* getHPoint_hsv64(const void* attr); static HPoint* getHPoint_hsv128(const void* attr); static HPoint* getHPoint_hsv256(const void* attr); static HPoint* getHPoint_lab256(const void* attr); /******************************************************************** distance functions for the picture type constructor: ********************************************************************/ template static void euclidean ( const DistData* dd1, const DistData* dd2, double &result); template static void quadr_hsv64 ( const DistData* dd1, const DistData* dd2, double &result); template static void quadr_hsv128 ( const DistData* dd1, const DistData* dd2, double &result); template static void quadr_hsv256 ( const DistData* dd1, const DistData* dd2, double &result); template static void quadr_lab256 ( const DistData* dd1, const DistData* dd2, double &result); private: /* Auxiliary methods, which compute the similarity arrays, if needed. */ static void computeHsv64SimMatrix(); static void computeHsv128SimMatrix(); static void computeHsv256SimMatrix(); static void computeLab256SimMatrix(); /******************************************************************** Computes the Eucledean-distance (and in particular the euclidean distance for n=2) ********************************************************************/ template inline static void computeEucledeanDist ( histDomain *v1, histDomain *v2, double &result); /******************************************************************** Computes the quadratic distance, using the given similarity matrix. ********************************************************************/ template static inline void computeQuadraticDist ( histDomain *v1, histDomain *v2, double &result); /******************************************************************** Encodes the histogram into a distdata object. ********************************************************************/ template static DistData* encodeHistogram ( unsigned long* hist_abs, unsigned numOfPixels, unsigned size, bool compressData, TFloat threshold = 5e-5); /******************************************************************** Decodes the histogram distdata object and writes the result to "hist"[4]. ********************************************************************/ template static void decodeHistogram ( TFloat* hist, const DistData* dd, unsigned size, bool compressedData); /******************************************************************** Auxiliary arrays for picture distfun: ********************************************************************/ static histDomain *simMatrix; static SIM_MATRIX_ID simMatrixId; static unsigned* pictureLabOffsetTable; }; // class PictureFuns /******************************************************************** 1.1 Implementation of inline and template methods ********************************************************************/ /* Method ~getData[_]hsv8~: */ template DistData* PictureFuns::getData_hsv8 (const void* attr) { unsigned long size; const char* imgdata = static_cast (attr)-> GetJPEGData (size); JPEGPicture rgb ((unsigned char *) imgdata, size); unsigned long int rgbSize; unsigned char* rgbData = rgb.GetImageData (rgbSize); const unsigned int numOfPixels = rgbSize / 3; unsigned long hist_abs[8]; memset (hist_abs, 0, 8*sizeof (unsigned long)); for (int i = 0; i < 8; ++i) hist_abs[i] = 0; for (unsigned long pos = 0; pos < (numOfPixels); ++pos) { unsigned char r = rgbData[ (3*pos) ]; unsigned char g = rgbData[ (3*pos) +1]; unsigned char b = rgbData[ (3*pos) +2]; HSV hsv (r, g, b); int h_offset = hsv.h / 180; // 2 parts int s_offset = hsv.s / 128; // 2 parts int v_offset = hsv.v / 256; // 2 parts ++hist_abs[4*h_offset + 2*s_offset + v_offset]; } return encodeHistogram ( hist_abs, numOfPixels, 8, compressData); } /* Method ~getData[_]hsv16~: */ template DistData* PictureFuns::getData_hsv16 (const void* attr) { unsigned long size; const char* imgdata = static_cast (attr)-> GetJPEGData (size); JPEGPicture rgb ((unsigned char *) imgdata, size); unsigned long int rgbSize; unsigned char* rgbData = rgb.GetImageData (rgbSize); const unsigned int numOfPixels = rgbSize / 3; unsigned long hist_abs[16]; memset (hist_abs, 0, 16*sizeof (unsigned long)); for (int i = 0; i < 16; ++i) hist_abs[i] = 0; for (unsigned long pos = 0; pos < (numOfPixels); ++pos) { unsigned char r = rgbData[ (3*pos) ]; unsigned char g = rgbData[ (3*pos) +1]; unsigned char b = rgbData[ (3*pos) +2]; HSV hsv (r, g, b); int h_offset = hsv.h / 90; // 4 parts int s_offset = hsv.s / 128; // 2 parts int v_offset = hsv.v / 256; // 2 parts ++hist_abs[4*h_offset + 2*s_offset + v_offset]; } return encodeHistogram ( hist_abs, numOfPixels, 16, compressData); } /* Method ~getData[_]hsv32~: */ template DistData* PictureFuns::getData_hsv32 (const void* attr) { unsigned long size; const char* imgdata = static_cast (attr)-> GetJPEGData (size); JPEGPicture rgb ((unsigned char *) imgdata, size); unsigned long int rgbSize; unsigned char* rgbData = rgb.GetImageData (rgbSize); const unsigned int numOfPixels = rgbSize / 3; unsigned long hist_abs[32]; memset (hist_abs, 0, 32*sizeof (unsigned long)); for (int i = 0; i < 32; ++i) hist_abs[i] = 0; for (unsigned long pos = 0; pos < (numOfPixels); ++pos) { unsigned char r = rgbData[ (3*pos) ]; unsigned char g = rgbData[ (3*pos) +1]; unsigned char b = rgbData[ (3*pos) +2]; HSV hsv (r, g, b); int h_offset = hsv.h / 90; // 4 parts int s_offset = hsv.s / 128; // 2 parts int v_offset = hsv.v / 128; // 4 parts ++hist_abs[8*h_offset + 4*s_offset + v_offset]; } return encodeHistogram ( hist_abs, numOfPixels, 32, compressData); } /* Method ~getData[_]hsv64~: */ template DistData* PictureFuns::getData_hsv64 (const void* attr) { unsigned long size; const char* imgdata = static_cast (attr)-> GetJPEGData (size); JPEGPicture rgb ((unsigned char *) imgdata, size); unsigned long int rgbSize; unsigned char* rgbData = rgb.GetImageData (rgbSize); const unsigned int numOfPixels = rgbSize / 3; unsigned long hist_abs[64]; memset (hist_abs, 0, 64*sizeof (unsigned long)); for (int i = 0; i < 64; ++i) hist_abs[i] = 0; for (unsigned long pos = 0; pos < (numOfPixels); ++pos) { unsigned char r = rgbData[ (3*pos) ]; unsigned char g = rgbData[ (3*pos) +1]; unsigned char b = rgbData[ (3*pos) +2]; HSV hsv (r, g, b); int h_offset = hsv.h / 90; // 4 parts int s_offset = hsv.s / 64; // 4 parts int v_offset = hsv.v / 128; // 4 parts ++hist_abs[16*h_offset + 4*s_offset + v_offset]; } return encodeHistogram ( hist_abs, numOfPixels, 64, compressData); } /* Method ~getData[_]hsv128~: */ template DistData* PictureFuns::getData_hsv128 (const void* attr) { unsigned long size; const char* imgdata = static_cast (attr)-> GetJPEGData (size); JPEGPicture rgb ((unsigned char *) imgdata, size); unsigned long int rgbSize; unsigned char* rgbData = rgb.GetImageData (rgbSize); const unsigned int numOfPixels = rgbSize / 3; unsigned long hist_abs[128]; memset (hist_abs, 0, 128*sizeof (unsigned long)); for (int i = 0; i < 128; ++i) hist_abs[i] = 0; for (unsigned long pos = 0; pos < (numOfPixels); ++pos) { unsigned char r = rgbData[ (3*pos) ]; unsigned char g = rgbData[ (3*pos) +1]; unsigned char b = rgbData[ (3*pos) +2]; HSV hsv (r, g, b); int h_offset = hsv.h / 45; // 8 parts int s_offset = hsv.s / 64; // 4 parts int v_offset = hsv.v / 128; // 4 parts ++hist_abs[16*h_offset + 4*s_offset + v_offset]; } return encodeHistogram ( hist_abs, numOfPixels, 128, compressData); } /* Method ~getData[_]hsv256~: */ template DistData* PictureFuns::getData_hsv256 (const void* attr) { unsigned long size; const char* imgdata = static_cast (attr)-> GetJPEGData (size); JPEGPicture rgb ((unsigned char *) imgdata, size); unsigned long int rgbSize; unsigned char* rgbData = rgb.GetImageData (rgbSize); const unsigned int numOfPixels = rgbSize / 3; unsigned long hist_abs[256]; memset (hist_abs, 0, 256*sizeof (unsigned long)); for (unsigned long pos = 0; pos < (numOfPixels); ++pos) { unsigned char r = rgbData[ (3*pos) ]; unsigned char g = rgbData[ (3*pos) +1]; unsigned char b = rgbData[ (3*pos) +2]; HSV hsv (r, g, b); int h_offset = (int) (hsv.h / 22.5); // 16 parts int s_offset = hsv.s / 64; // 4 parts int v_offset = hsv.v / 128; // 4 parts ++hist_abs[16*h_offset + 4*s_offset + v_offset]; } return encodeHistogram ( hist_abs, numOfPixels, 256, compressData); } /* Method ~getData[_]lab256~: */ template DistData* PictureFuns::getData_lab256 (const void* attr) { if (!pictureLabOffsetTable) { pictureLabOffsetTable = new unsigned[64*64*64]; for (signed char r = 0; r < 64; r++) for (signed char g = 0; g < 64; g++) for (signed char b = 0; b < 64; b++) { Lab lab (2 + (r*4), 2 + (g*4), 2 + (b*4)); // map values [0, 99] x [-86, 98] x [-107,94] to // [0, 3] x [0, 7] x [0, 7] (4 x 8 x 8 = 256 bins) int L_offset = (int) (lab.L / 25); int a_offset = (int) ((lab.a + 86) / 23.125); int b_offset = (int) ((lab.b + 107) / 25.1); pictureLabOffsetTable[r*4096 + g*64 + b] = 64 * L_offset + 8 * a_offset + b_offset; } } unsigned long size; const char* imgdata = static_cast (attr)-> GetJPEGData (size); JPEGPicture rgb ((unsigned char *) imgdata, size); unsigned long int rgbSize; unsigned char* rgbData = rgb.GetImageData (rgbSize); const unsigned int numOfPixels = rgbSize / 3; unsigned long hist_abs[256]; memset (hist_abs, 0, 256*sizeof (unsigned long)); for (unsigned long pos = 0; pos < numOfPixels; ++pos) { unsigned char r = static_cast (rgbData[ (3*pos) ] / 4); unsigned char g = static_cast (rgbData[ (3*pos) +1] / 4); unsigned char b = static_cast (rgbData[ (3*pos) +2] / 4); ++hist_abs[pictureLabOffsetTable[ (r*4096) + (g*64) + b] ]; } delete[] imgdata; return encodeHistogram ( hist_abs, numOfPixels, 256, compressData); } // euclidean distance functions template void PictureFuns::euclidean ( const DistData* dd1, const DistData* dd2, double &result) { histDomain hist1[dim]; histDomain hist2[dim]; decodeHistogram (hist1, dd1, dim, compressedData); decodeHistogram (hist2, dd2, dim, compressedData); computeEucledeanDist(hist1, hist2, result); } /* Method ~quadr[_]hsv64~: */ template void PictureFuns::quadr_hsv64 ( const DistData* dd1, const DistData* dd2, double &result) { if (simMatrixId != SIM_MATRIX_HSV64) computeHsv64SimMatrix(); histDomain hist1[64]; histDomain hist2[64]; decodeHistogram (hist1, dd1, 64, compressedData); decodeHistogram (hist2, dd2, 64, compressedData); computeQuadraticDist<64>(hist1, hist2, result); } /* Method ~quadr[_]hsv128~: */ template void PictureFuns::quadr_hsv128 ( const DistData* dd1, const DistData* dd2, double &result) { if (simMatrixId != SIM_MATRIX_HSV128) computeHsv128SimMatrix(); histDomain hist1[128]; histDomain hist2[128]; decodeHistogram (hist1, dd1, 128, compressedData); decodeHistogram (hist2, dd2, 128, compressedData); computeQuadraticDist<128>(hist1, hist2, result); } /* Method ~quadr[_]hsv256~: */ template void PictureFuns::quadr_hsv256 ( const DistData* dd1, const DistData* dd2, double &result) { if (simMatrixId != SIM_MATRIX_HSV256) computeHsv256SimMatrix(); histDomain hist1[256]; histDomain hist2[256]; decodeHistogram (hist1, dd1, 256, compressedData); decodeHistogram (hist2, dd2, 256, compressedData); computeQuadraticDist<256>( hist1, hist2, result); } /* Method ~quadr[_]lab256~: */ template void PictureFuns::quadr_lab256 ( const DistData* dd1, const DistData* dd2, double &result) { if (simMatrixId != SIM_MATRIX_LAB256) computeLab256SimMatrix(); histDomain hist1[256]; histDomain hist2[256]; decodeHistogram (hist1, dd1, 256, compressedData); decodeHistogram (hist2, dd2, 256, compressedData); computeQuadraticDist<256>( hist1, hist2, result); } /* Method ~computeEucledeanDist~: */ template void PictureFuns::computeEucledeanDist ( histDomain *v1, histDomain *v2, double &result) { result = 0; for (unsigned pos = 0; pos < dim; ++pos) result += std::pow(std::abs (v1[pos] - v2[pos]), 2); result = std::sqrt(result); } /* Method ~computeQuadraticDist~: */ template void PictureFuns::computeQuadraticDist ( histDomain *v1, histDomain *v2, double &result) { histDomain diff[dim]; unsigned first = 0; unsigned last = dim - 1; for (unsigned pos = 0; pos < dim; ++pos) { diff[pos] = v1[pos] - v2[pos]; } while (last > 0 && !diff[last]) --last; while (first < last && !diff[first]) ++first; result = 0; for (unsigned pos1 = first; pos1 < last; ++pos1) for (unsigned pos2 = first; pos2 < last; ++pos2) result += diff[pos1] * diff[pos2] * simMatrix[ (pos1*dim) +pos2]; result = std::sqrt(result); } /* Method ~encodeHistogram~: */ template DistData* PictureFuns::encodeHistogram ( unsigned long* hist_abs, unsigned numOfPixels, unsigned size, bool compressData, TFloat threshold) { TFloat hist[size]; std::list indizes; indizes.push_back (0); bool isZeroValue = true; for (unsigned i = 0; i < size; ++i) { hist[i] = (TFloat) hist_abs[i] / numOfPixels; if (hist[i] < threshold) hist[i] = 0; if (isZeroValue != (hist[i] == 0)) { isZeroValue = !isZeroValue; indizes.push_back (0); } if (indizes.back() < std::numeric_limits::max()) { ++indizes.back(); } else { indizes.push_back (0); indizes.push_back (1); } } if (!compressData) return new DistData (size*sizeof (TFloat), &hist); // count sum of histogram entries unsigned sum = 0; // sum of non zero entries unsigned sum2 = 0; // sum of all entries bool evenValue = false; for (std::list::iterator it = indizes.begin(); it != indizes.end(); ++it) { if (evenValue) sum += *it; sum2 += *it; evenValue = !evenValue; } assert (sum2 == size); char result[sizeof (int) + indizes.size() *sizeof (char) + sum*sizeof (TFloat) ]; int indexCount = indizes.size(); memcpy (result, &indexCount, sizeof (int)); int offset = sizeof (int); for (std::list::iterator it = indizes.begin(); it != indizes.end(); ++it) { unsigned char index = *it; memcpy (result + offset, &index, sizeof (char)); offset += sizeof (char); } // copy non zero histogram values to result buffer unsigned histPos = 0; std::list::iterator it = indizes.begin(); while (histPos < size) { histPos += *it; ++it; if (it != indizes.end()) { unsigned j = histPos + *it; ++it; for (;histPos < j; ++histPos) { memcpy (result + offset, &hist[histPos], sizeof (TFloat)); offset += sizeof (TFloat); } } } return new DistData (offset, result); } /* Method ~decodeHistogram~: */ template void PictureFuns::decodeHistogram ( TFloat* hist, const DistData* dd, unsigned size, bool compressedData) { const char* data = static_cast (dd->value()); if (!compressedData) { memcpy (hist, data, size*sizeof (TFloat)); return; } memset (hist, 0, size*sizeof (TFloat)); int cnt; memcpy (&cnt, data, sizeof (int)); int offset = sizeof (int); unsigned char indizes[cnt]; memcpy (indizes, data + offset, cnt*sizeof (char)); offset += cnt * sizeof (char); unsigned histPos = 0; int i = -1; while (histPos < size) { histPos += indizes[++i]; if (++i < cnt) { unsigned j = histPos + indizes[i]; for (;histPos < j; ++histPos) { memcpy (&hist[histPos], data + offset, sizeof (TFloat)); offset += sizeof (TFloat); } } } } } // namespace gta #endif // #ifndef __PICTURE_FUNCTIONS_H__