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