Files
secondo/Algebras/GeneralTree/PictureFuns.h
2026-01-23 17:03:45 +08:00

860 lines
24 KiB
C++

/*
----
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 <limits>
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<bool compressData>
static DistData* getData_hsv8(const void* attr);
template<bool compressData>
static DistData* getData_hsv16(const void* attr);
template<bool compressData>
static DistData* getData_hsv32(const void* attr);
template<bool compressData>
static DistData* getData_hsv64(const void* attr);
template<bool compressData>
static DistData* getData_hsv128(const void* attr);
template<bool compressData>
static DistData* getData_hsv256(const void* attr);
template<bool compressData>
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<unsigned dim, bool compressedData>
static void euclidean (
const DistData* dd1, const DistData* dd2,
double &result);
template<bool compressedData>
static void quadr_hsv64 (
const DistData* dd1, const DistData* dd2,
double &result);
template<bool compressedData>
static void quadr_hsv128 (
const DistData* dd1, const DistData* dd2,
double &result);
template<bool compressedData>
static void quadr_hsv256 (
const DistData* dd1, const DistData* dd2,
double &result);
template<bool compressedData>
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<unsigned dim>
inline static void computeEucledeanDist (
histDomain *v1, histDomain *v2, double &result);
/********************************************************************
Computes the quadratic distance, using the given similarity matrix.
********************************************************************/
template<unsigned dim>
static inline void computeQuadraticDist (
histDomain *v1, histDomain *v2, double &result);
/********************************************************************
Encodes the histogram into a distdata object.
********************************************************************/
template<class TFloat>
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<class TFloat>
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<bool compressData> DistData*
PictureFuns::getData_hsv8 (const void* attr)
{
unsigned long size;
const char* imgdata = static_cast<const Picture*> (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<histDomain> (
hist_abs, numOfPixels, 8, compressData);
}
/*
Method ~getData[_]hsv16~:
*/
template<bool compressData> DistData*
PictureFuns::getData_hsv16 (const void* attr)
{
unsigned long size;
const char* imgdata = static_cast<const Picture*> (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<histDomain> (
hist_abs, numOfPixels, 16, compressData);
}
/*
Method ~getData[_]hsv32~:
*/
template<bool compressData> DistData*
PictureFuns::getData_hsv32 (const void* attr)
{
unsigned long size;
const char* imgdata = static_cast<const Picture*> (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<histDomain> (
hist_abs, numOfPixels, 32, compressData);
}
/*
Method ~getData[_]hsv64~:
*/
template<bool compressData> DistData*
PictureFuns::getData_hsv64 (const void* attr)
{
unsigned long size;
const char* imgdata = static_cast<const Picture*> (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<histDomain> (
hist_abs, numOfPixels, 64, compressData);
}
/*
Method ~getData[_]hsv128~:
*/
template<bool compressData> DistData*
PictureFuns::getData_hsv128 (const void* attr)
{
unsigned long size;
const char* imgdata = static_cast<const Picture*> (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<histDomain> (
hist_abs, numOfPixels, 128, compressData);
}
/*
Method ~getData[_]hsv256~:
*/
template<bool compressData> DistData*
PictureFuns::getData_hsv256 (const void* attr)
{
unsigned long size;
const char* imgdata = static_cast<const Picture*> (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<histDomain> (
hist_abs, numOfPixels, 256, compressData);
}
/*
Method ~getData[_]lab256~:
*/
template<bool compressData> 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<const Picture*> (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<unsigned char>
(rgbData[ (3*pos) ] / 4);
unsigned char g = static_cast<unsigned char>
(rgbData[ (3*pos) +1] / 4);
unsigned char b = static_cast<unsigned char>
(rgbData[ (3*pos) +2] / 4);
++hist_abs[pictureLabOffsetTable[ (r*4096) + (g*64) + b] ];
}
delete[] imgdata;
return encodeHistogram<histDomain> (
hist_abs, numOfPixels, 256, compressData);
}
// euclidean distance functions
template<unsigned dim, bool compressedData> void
PictureFuns::euclidean (
const DistData* dd1, const DistData* dd2, double &result)
{
histDomain hist1[dim];
histDomain hist2[dim];
decodeHistogram<histDomain> (hist1, dd1, dim, compressedData);
decodeHistogram<histDomain> (hist2, dd2, dim, compressedData);
computeEucledeanDist<dim>(hist1, hist2, result);
}
/*
Method ~quadr[_]hsv64~:
*/
template<bool compressedData> 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<histDomain> (hist1, dd1, 64, compressedData);
decodeHistogram<histDomain> (hist2, dd2, 64, compressedData);
computeQuadraticDist<64>(hist1, hist2, result);
}
/*
Method ~quadr[_]hsv128~:
*/
template<bool compressedData> 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<histDomain> (hist1, dd1, 128, compressedData);
decodeHistogram<histDomain> (hist2, dd2, 128, compressedData);
computeQuadraticDist<128>(hist1, hist2, result);
}
/*
Method ~quadr[_]hsv256~:
*/
template<bool compressedData> 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<histDomain> (hist1, dd1, 256, compressedData);
decodeHistogram<histDomain> (hist2, dd2, 256, compressedData);
computeQuadraticDist<256>( hist1, hist2, result);
}
/*
Method ~quadr[_]lab256~:
*/
template<bool compressedData> 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<histDomain> (hist1, dd1, 256, compressedData);
decodeHistogram<histDomain> (hist2, dd2, 256, compressedData);
computeQuadraticDist<256>( hist1, hist2, result);
}
/*
Method ~computeEucledeanDist~:
*/
template<unsigned dim> 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<unsigned dim> 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<class TFloat> DistData*
PictureFuns::encodeHistogram (
unsigned long* hist_abs, unsigned numOfPixels,
unsigned size, bool compressData, TFloat threshold)
{
TFloat hist[size];
std::list<unsigned char> 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<unsigned char>::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<unsigned char>::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<unsigned char>::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<unsigned char>::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<class TFloat> void
PictureFuns::decodeHistogram (
TFloat* hist, const DistData* dd, unsigned size,
bool compressedData)
{
const char* data = static_cast<const char*> (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__