00001 #ifndef Impala_Core_Feature_Color64_h
00002 #define Impala_Core_Feature_Color64_h
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "Basis/String.h"
00019 #include "Core/Database/RawDataSet.h"
00020 #include "Core/Feature/FeatureDefinition.h"
00021 #include "Core/Vector/VectorTem.h"
00022 #include "Core/Feature/FeatureTable.h"
00023 #include "Core/Feature/Grid.h"
00024
00025 #define BYTE unsigned char
00026 #define BOOL bool
00027 #define UINT unsigned int
00028
00029 #ifndef max
00030 #define max(a,b) (((a) > (b)) ? (a) : (b))
00031 #endif
00032
00033 #ifndef min
00034 #define min(a,b) (((a) < (b)) ? (a) : (b))
00035 #endif
00036
00037 namespace Impala
00038 {
00039 namespace Core
00040 {
00041 namespace Feature
00042 {
00043
00044
00045 class Color64
00046 {
00047 public:
00048
00049 Color64(String featureName="color64")
00050 {
00051 mFeatureName = featureName;
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 SetFeatureMode();
00064
00065 mFeature = new float [64];
00066
00067
00068
00069 }
00070
00071 ~Color64()
00072 {
00073 delete mFeature;
00074
00075
00076 }
00077
00078 String
00079 GetName() const
00080 {
00081 return mFeatureName;
00082 }
00083
00084 void
00085 SetGridDimension(int nRow, int nCol)
00086 {
00087 mRow = nRow;
00088 mCol = nCol;
00089 }
00090
00091 int
00092 Extract(Core::Array::Array2dVec3UInt8* im, Core::Vector::VectorReal64& histogram)
00093 {
00094 switch (mode)
00095 {
00096 case 1:
00097
00098 ExtractCorrelogramTextureMoment(im->CPB(), im->CW(), im->CH(), mFeature, 1);
00099
00100 for (int d=0; d<44; d++)
00101 {
00102 histogram[d] = mFeature[d];
00103 }
00104
00105 VerifyFeatureRange(mFeature, 44);
00106
00107 break;
00108
00109 case 2:
00110
00111 ExtractCorrelogramTextureMoment(im->CPB(), im->CW(), im->CH(), mFeature, 2);
00112 for (int d=0; d<14; d++)
00113 {
00114 histogram[d] = mFeature[d+44];
00115 }
00116
00117 VerifyFeatureRange(mFeature+44,14);
00118 break;
00119
00120 case 3:
00121
00122 ExtractCorrelogramTextureMoment(im->CPB(), im->CW(), im->CH(), mFeature, 3);
00123 for (int d=0; d<6; d++)
00124 {
00125 histogram[d] = mFeature[d+44+14];
00126 }
00127
00128 VerifyFeatureRange(mFeature+44+14, 6);
00129 break;
00130
00131 case 4:
00132
00133 ComputeGrid(im, histogram, 2, 2);
00134
00135 break;
00136
00137 case 5:
00138
00139 ComputeGrid(im, histogram, 3, 3);
00140
00141 break;
00142
00143 case 6:
00144
00145 ComputeGrid(im, histogram, 4, 4);
00146
00147 break;
00148
00149 default:
00150
00151 ExtractCorrelogramTextureMoment(im->CPB(), im->CW(), im->CH(), mFeature);
00152
00153 for (int d=0; d<64; d++)
00154 {
00155 histogram[d] = mFeature[d];
00156 }
00157
00158 VerifyFeatureRange(mFeature, 64);
00159
00160 break;
00161 }
00162
00163 return 0;
00164 }
00165
00166 void
00167 ComputeGrid(Core::Array::Array2dVec3UInt8* im, Core::Vector::VectorReal64& histogram, int nRow, int nCol)
00168 {
00169 SetGridDimension(nRow, nCol);
00170
00171 Core::Feature::Grid* pGrid = new Core::Feature::Grid(mRow, mCol);
00172
00173 BYTE** grid_buffers= new BYTE* [mRow*mCol];
00174 int nGridWidth = (im->CW()/mCol);
00175 int nGridHeight = (im->CH()/mRow);
00176 for (int k=0; k< mRow*mCol; k++)
00177 {
00178 grid_buffers[k] = new BYTE[nGridWidth*nGridHeight*3];
00179 }
00180
00181 pGrid->RetrievalGridBuffers( (BYTE*)im->CPB(), grid_buffers, im->CW(), im->CH());
00182
00183
00184 for (int k=0; k< mRow*mCol; k++)
00185 {
00186 ExtractCorrelogramTextureMoment(grid_buffers[k], nGridWidth, nGridHeight, mFeature);
00187 for (int d=0; d<64; d++)
00188 {
00189 histogram[k*64+d] = mFeature[d];
00190 }
00191
00192 VerifyFeatureRange(mFeature, 64);
00193
00194 }
00195
00196 for (int k=0; k< mRow*mCol; k++)
00197 {
00198 delete [](grid_buffers[k]);
00199 }
00200 delete []grid_buffers;
00201 delete pGrid;
00202
00203 }
00204
00205 void
00206 SetFeatureMode()
00207 {
00208
00209 if (mFeatureName == "correlogram44")
00210 {
00211 mode=1;
00212 mBinCount = 44;
00213 }
00214 else if (mFeatureName == "texturemoment14")
00215 {
00216 mode=2;
00217 mBinCount = 14;
00218 }
00219 else if (mFeatureName == "rgbmoment6")
00220 {
00221 mode=3;
00222 mBinCount = 6;
00223 }
00224 else if (mFeatureName == "color64grid2x2")
00225 {
00226 mode=4;
00227 mBinCount = 64*2*2;
00228 }
00229 else if (mFeatureName == "color64grid3x3")
00230 {
00231 mode=5;
00232 mBinCount = 64*3*3;
00233 }
00234 else if (mFeatureName == "color64grid4x4")
00235 {
00236 mode=6;
00237 mBinCount = 64*4*4;
00238 }
00239 else if (mFeatureName == "")
00240 {
00241 mode=-1;
00242 mBinCount = 0;
00243 }
00244 else
00245 {
00246 mode=0;
00247 mBinCount = 64;
00248 }
00249 }
00250
00251
00252
00253
00254 int ExtractCorrelogramTextureMoment(BYTE *pImage, int nWidth, int nHeight, void *pFeature, int mode=0)
00255 {
00256 if (pFeature == 0)
00257 {
00258 return -1;
00259 }
00260 memset(pFeature, 0, sizeof(float) * 64);
00261
00262 if (nWidth < 3 || nHeight < 3)
00263 {
00264 return -1;
00265 }
00266
00267 float* pfCorrelogram44 = (float*)pFeature;
00268 float* pfTextureMoment = pfCorrelogram44 + 44;
00269 float* pfColorMoment = pfTextureMoment + 14;
00270
00271 float* pfImage = new float[nWidth * nHeight];
00272 BYTE* pbImage = new BYTE[nWidth * nHeight];
00273
00274 if (pbImage != NULL && pfImage != NULL)
00275 {
00276 for (int y = 0; y < nHeight; y ++)
00277 {
00278 float* pf = pfImage + y * nWidth;
00279 BYTE* pb = pbImage + y * nWidth;
00280
00281 for (int x = 0; x < nWidth; x ++)
00282 {
00283
00284 BYTE r = pImage[(y*nWidth+x)*3+0];
00285 BYTE g = pImage[(y*nWidth+x)*3+1];
00286 BYTE b = pImage[(y*nWidth+x)*3+2];
00287
00288 pf[x] =(float) r + g + b;
00289 pb[x] = QuantizeColorHSV44(r, g, b);
00290
00291 pfColorMoment[0] += r;
00292 pfColorMoment[1] += g;
00293 pfColorMoment[2] += b;
00294
00295 pfColorMoment[3] += r * r;
00296 pfColorMoment[4] += g * g;
00297 pfColorMoment[5] += b * b;
00298 }
00299 }
00300
00301 float fArea =(float) nWidth * nHeight;
00302
00303 switch (mode)
00304 {
00305 case 1:
00306
00307 ExtractCorrelogram50(pbImage, nWidth, nHeight, pfCorrelogram44);
00308 break;
00309
00310 case 2:
00311
00312 ExtractTextureMoment(pfImage, nWidth, nHeight, pfTextureMoment);
00313 break;
00314
00315 case 3:
00316
00317 for (int i = 0; i < 3; i ++)
00318 {
00319 pfColorMoment[i] /= fArea;
00320 pfColorMoment[i + 3] = pfColorMoment[i + 3] / fArea - pfColorMoment[i] * pfColorMoment[i];
00321 pfColorMoment[i + 3] = (float)sqrt(fabs(pfColorMoment[i + 3]));
00322 }
00323 NormalizeVector(pfColorMoment, 6);
00324 break;
00325
00326 default:
00327
00328 ExtractCorrelogram50(pbImage, nWidth, nHeight, pfCorrelogram44);
00329 ExtractTextureMoment(pfImage, nWidth, nHeight, pfTextureMoment);
00330
00331 for (int i = 0; i < 3; i ++)
00332 {
00333 pfColorMoment[i] /= fArea;
00334 pfColorMoment[i + 3] = pfColorMoment[i + 3] / fArea - pfColorMoment[i] * pfColorMoment[i];
00335 pfColorMoment[i + 3] = (float)sqrt(fabs(pfColorMoment[i + 3]));
00336 }
00337 NormalizeVector(pfColorMoment, 6);
00338
00339 break;
00340 }
00341
00342 }
00343 if (pbImage != NULL)
00344 {
00345 delete []pbImage;
00346 }
00347 if (pfImage != NULL)
00348 {
00349 delete []pfImage;
00350 }
00351
00352 return 0;
00353 }
00354
00355 void ExtractCorrelogram50(BYTE* pbImage, int nWidth, int nHeight, float* pfFeature)
00356 {
00357 float afHistogram[50], afCorrelogram[50];
00358 memset(afHistogram, 0, sizeof(afHistogram));
00359 memset(afCorrelogram, 0, sizeof(afCorrelogram));
00360
00361 for (int y = 1; y < nHeight - 1; y ++)
00362 {
00363 BYTE* pbCurr = pbImage + y * nWidth;
00364 BYTE* pbPrev = pbCurr - nWidth;
00365 BYTE* pbNext = pbCurr + nWidth;
00366
00367 for (int x = 1; x < nWidth - 1; x ++)
00368 {
00369
00370 int nIndex = pbCurr[x];
00371 int nCount = (pbPrev[x - 1] == nIndex) + (pbPrev[x] == nIndex) + (pbPrev[x + 1] == nIndex)
00372 + (pbCurr[x - 1] == nIndex) + (pbCurr[x + 1] == nIndex)
00373 + (pbNext[x - 1] == nIndex) + (pbNext[x] == nIndex) + (pbNext[x + 1] == nIndex);
00374 afHistogram[nIndex] ++;
00375 afCorrelogram[nIndex] += nCount;
00376 }
00377 }
00378
00379 for (int i = 0; i < 50; i ++)
00380 {
00381 if (afHistogram[i] > 0)
00382 {
00383 pfFeature[i] = afCorrelogram[i] / afHistogram[i];
00384 }
00385 }
00386 NormalizeVector(pfFeature, 50);
00387 }
00388
00389 void ExtractTextureMoment(float* pfImage, int nWidth, int nHeight, float* pfFeature)
00390 {
00391 const float fW2 = (float)sqrt(2.0);
00392 for (int y = 1; y < nHeight - 1; y ++)
00393 {
00394 float* pfCurr = pfImage + y * nWidth;
00395 float* pfPrev = pfCurr - nWidth;
00396 float* pfNext = pfCurr + nWidth;
00397
00398 for (int x = 1; x < nWidth - 1; x ++)
00399 {
00400 float af[8];
00401
00402 af[0] = pfPrev[x - 1] + pfPrev[x] + pfPrev[x + 1]
00403 + pfCurr[x - 1] + pfCurr[x + 1]
00404 + pfNext[x - 1] + pfNext[x] + pfNext[x + 1];
00405
00406 af[1] = - pfPrev[x - 1] + pfPrev[x] - pfPrev[x + 1]
00407 + pfCurr[x - 1] + pfCurr[x + 1]
00408 - pfNext[x - 1] + pfNext[x] - pfNext[x + 1];
00409
00410 af[2] = - pfPrev[x - 1] + pfPrev[x + 1] - pfNext[x - 1] + pfNext[x + 1]
00411 + fW2 * (- pfCurr[x - 1] + pfCurr[x + 1]);
00412
00413 af[3] = - pfPrev[x - 1] - pfPrev[x + 1] + pfNext[x - 1] + pfNext[x + 1]
00414 + fW2 * (- pfPrev[x] + pfNext[x]);
00415
00416 af[4] = fW2 * (- pfPrev[x] + pfCurr[x - 1] + pfCurr[x + 1] - pfNext[x]);
00417
00418 af[5] = fW2 * (pfPrev[x - 1] - pfPrev[x + 1] - pfNext[x - 1] + pfNext[x + 1]);
00419
00420 af[6] = pfPrev[x - 1] - pfPrev[x + 1] + pfNext[x - 1] - pfNext[x + 1]
00421 + fW2 * (- pfCurr[x - 1] + pfCurr[x + 1]);
00422
00423 af[7] = - pfPrev[x - 1] - pfPrev[x + 1] + pfNext[x - 1] + pfNext[x + 1]
00424 + fW2 * (pfPrev[x] - pfNext[x]);
00425
00426
00427
00428
00429
00430
00431
00432
00433 for (int i = 1; i < 8; i ++)
00434 {
00435
00436 pfFeature[i - 1] += fabs(af[i]);
00437 pfFeature[i + 6] += af[i] * af[i];
00438 }
00439 }
00440 }
00441
00442 float fSizeNorm = 1.0f / ((nWidth - 2) * (nHeight - 2));
00443 for (int i = 0; i < 7; i ++)
00444 {
00445 pfFeature[i] *= fSizeNorm;
00446 pfFeature[i + 7] = (float)sqrt(fabs(pfFeature[i + 7] * fSizeNorm - pfFeature[i] * pfFeature[i]));
00447 }
00448 NormalizeVector(pfFeature, 14);
00449 }
00450
00451 void NormalizeVector(float* pf, int nLen)
00452 {
00453 if (pf != NULL && nLen > 0)
00454 {
00455 float f = 0;
00456 for (int i = 0; i < nLen; i ++)
00457 {
00458 f += pf[i] * pf[i];
00459 }
00460 f = sqrt(f);
00461 if (f < 1e-4f)
00462 {
00463 f = 1e-4f;
00464 }
00465 for (int i = 0; i < nLen; i ++)
00466 {
00467 pf[i] /= (float)f;
00468 }
00469 }
00470 }
00471
00472 int QuantizeColorHSV44(BYTE bRed, BYTE bGreen, BYTE bBlue)
00473 {
00474 static BYTE RGB2HSV[16][16][16];
00475 static bool bInit = false;
00476 if (!bInit)
00477 {
00478 for (int r = 0; r < 16; r ++)
00479 {
00480 for (int g = 0; g < 16; g ++)
00481 {
00482 for (int b = 0; b < 16; b ++)
00483 {
00484 int nMax = max(r, max(g, b));
00485 int nMin = min(r, min(g, b));
00486
00487 float h, s, v;
00488 if (nMax == nMin)
00489 {
00490 h = 0;
00491 }
00492 else if (r == nMin)
00493 {
00494 h = 3.0f + (float)(b - g) / (nMax - nMin);
00495 }
00496 else if (g == nMin)
00497 {
00498 h = 5.0f + (float)(r - b) / (nMax - nMin);
00499 }
00500 else
00501 {
00502 h = 1.0f + (float)(g - r) / (nMax - nMin);
00503 }
00504 if (nMax > 0)
00505 {
00506 s = (float)(nMax - nMin) / nMax;
00507 }
00508 else
00509 {
00510 s = 0;
00511 }
00512 v = (float)nMax / 15.0f;
00513
00514 int H = (int)(h * 60);
00515 int S = (int)(s * 10);
00516 int V = (int)(v * 10);
00517 int nIndex;
00518
00519 if (V < 2)
00520 {
00521 nIndex = 0;
00522 }
00523 else if (S < 2)
00524 {
00525 if (V < 8)
00526 {
00527 nIndex = V - 1;
00528 }
00529 else
00530 {
00531 nIndex = 7 + (V >= 9);
00532 }
00533 }
00534 else
00535 {
00536 int nColor;
00537 if (H < 22)
00538 {
00539 nColor = 0;
00540 }
00541 else if (H < 45)
00542 {
00543 nColor = 1;
00544 }
00545 else if (H < 70)
00546 {
00547 nColor = 2;
00548 }
00549 else if (H < 155)
00550 {
00551 nColor = 3;
00552 }
00553 else if (H < 186)
00554 {
00555 nColor = 4;
00556 }
00557 else if (H < 278)
00558 {
00559 nColor = 5;
00560 }
00561 else if (H < 330)
00562 {
00563 nColor = 6;
00564 }
00565 else
00566 {
00567 nColor = 0;
00568 }
00569
00570 if (V >= 7)
00571 {
00572 nIndex = 2 + (S >= 5) + (S >= 8);
00573 }
00574 else
00575 {
00576 nIndex = (S >= 7);
00577 }
00578 nIndex += 9 + 5 * nColor;
00579 }
00580 RGB2HSV[r][g][b] = nIndex;
00581 }
00582 }
00583 }
00584 bInit = true;
00585 }
00586 return RGB2HSV[bRed / 16][bGreen / 16][bBlue / 16];
00587 }
00588
00589 bool VerifyFeatureSum(float* pFeature, int nDim, float ref=1.0)
00590 {
00591 float sum = 0;
00592 for (int i=0; i<nDim; i++)
00593 {
00594 sum += pFeature[i];
00595 }
00596
00597 float diff = sum-ref;
00598 if ( fabs(diff) < 1e-10 )
00599 return true;
00600 else
00601 {
00602 std::cout << "ERROR: Feature Sum Verifiction failed." << std::endl;
00603 return false;
00604 }
00605
00606 }
00607
00608 bool VerifyFeatureRange(float* pFeature, int nDim, float min=0, float max=1.0)
00609 {
00610 float sum = 0;
00611 for (int i=0; i<nDim; i++)
00612 {
00613 float value = pFeature[i];
00614 if (value< min || value > max )
00615 {
00616 std::cout << "ERROR: Feature Range Verifiction failed: " << value << std::endl;
00617 return false;
00618 }
00619 }
00620
00621 return true;
00622 }
00623
00624 private:
00625
00626 Database::RawDataSet* mDataSet;
00627 String mFeatureName;
00628 int mode;
00629 float* mFeature;
00630
00631 int mBinCount;
00632
00633 int mRow;
00634 int mCol;
00635
00636 };
00637
00638 }
00639 }
00640 }
00641
00642 #endif