Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

Color64.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Feature_Color64_h
00002 #define Impala_Core_Feature_Color64_h
00003 
00004 // extract color 64 bin features, provided by xirong.
00005 // color64: 44-d color correlgoram, 14-d color texture moment, and 6-d RGB color moment
00006 
00007 // Color correlgoram:
00008 // J. Huang, S. Kumar, M. Mitra, W. Zhu, and R. Zabih, “Image indexing using color correlograms,” in Proc. CVPR, 1997, pp. 762–768.
00009 // Color texture:
00010 // H. Yu, M. Li, H. Zhang, and J. Feng, “Color texture moment for contentbased image retrieval,” in Proc. ICIP, 2002, pp. 929–932.
00011 //
00012 // We have used this simple color64 feature a few times in the past, with a moderate success for large-scale web image retrieval, e.g.,
00013 // http://staff.science.uva.nl/~xirong/pub/li-tag-double.pdf.
00014 // For each image, we extract 44-d color correlgoram [44], 14-d color texture moment [45], and 6-d RGB color moment. 
00015 // We separately normalize the three features into unit length and concatenate them into a single vector. 
00016 // We use the Euclidean distance as a dissimilarity measurement.
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         // set the feature mode based on mFeatureName as: 0, 1, 2, 3, 4
00054         //
00055         // mode=0: color64
00056         // mode=1: 44-d color correlogram
00057         // mode=2: 14-d color texture moment
00058         // mode=3: 6-d RGB color moment
00059         // mode=4: color64 grid 2x2
00060         // mode=5: color64 grid 3x3
00061         // mode=6: color64 grid 4x4
00062         //
00063         SetFeatureMode();
00064 
00065         mFeature = new float [64];
00066 
00067         //mGrid = new Core::Feature::Grid(2,2);
00068 
00069     }
00070 
00071     ~Color64()
00072     {
00073         delete mFeature;
00074 
00075         //delete mGrid;
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: // 44-d color correlogram
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              //VerifyFeatureSum(mFeature, 44, 1);
00105              VerifyFeatureRange(mFeature, 44);
00106 
00107              break;
00108 
00109          case 2: // 14-d color texture moment
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              //VerifyFeatureSum(mFeature+44, 14, 1);
00117              VerifyFeatureRange(mFeature+44,14);
00118              break;
00119 
00120          case 3: // 6-d RGB color moment
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              //VerifyFeatureSum(mFeature+44+14, 6, 1);
00128              VerifyFeatureRange(mFeature+44+14, 6);
00129              break;
00130 
00131          case 4: // 256-d color64 grid 2x2
00132 
00133              ComputeGrid(im, histogram, 2, 2);             
00134 
00135              break;
00136 
00137          case 5: // 576-d color64 grid 3x3
00138              
00139              ComputeGrid(im, histogram, 3, 3);
00140 
00141              break;
00142 
00143          case 6: // 1024-d color64 grid 4x4
00144              
00145              ComputeGrid(im, histogram, 4, 4);
00146 
00147              break;
00148 
00149          default: // "color64", 64dim = 44+14+6
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              //VerifyFeatureSum(mFeature, 64, 3);
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          //VerifyFeatureSum(mFeature, 64, 3);
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         //int mode=0;
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 // "color64"
00245         {
00246             mode=0;
00247             mBinCount = 64;
00248         }
00249     }
00250 
00251     // Main Function for the "color64" feature extraction
00252     //
00253     // mode: see SetFeatureMode()
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                     // Note: the order of the buffer is RGBRGB...
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: // 44-d color correlogram
00306 
00307                 ExtractCorrelogram50(pbImage, nWidth, nHeight, pfCorrelogram44);
00308                 break;
00309 
00310              case 2: // 14-d color texture moment
00311 
00312                 ExtractTextureMoment(pfImage, nWidth, nHeight, pfTextureMoment);
00313                 break;
00314 
00315              case 3: // 6-d RGB color moment
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: // color64 = 44+14+6
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                 // Note: nIndex = [0,43]
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                 /*float fValueNorm = af[0];
00427                 if (fValueNorm < 1e-4f)
00428                 {
00429                     fValueNorm = 1e-4f;
00430                 }
00431                 fValueNorm = 1.0f / fValueNorm;
00432                 */
00433                 for (int i = 1; i < 8; i ++)
00434                 {
00435                     //af[i] *= fValueNorm;
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 //if (b == nMin)
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)     // black area
00520                         {
00521                             nIndex = 0;
00522                         }
00523                         else if (S < 2) // Gray area
00524                         {
00525                             if (V < 8)
00526                             {
00527                                 nIndex = V - 1; // 1~6, gray area
00528                             }
00529                             else
00530                             {
00531                                 nIndex = 7 + (V >= 9);   // 7~8, white area
00532                             }
00533                         }
00534                         else // Color area
00535                         {
00536                             int nColor;
00537                             if (H < 22)
00538                             {
00539                                 nColor = 0; // red
00540                             }
00541                             else if (H < 45)
00542                             {
00543                                 nColor = 1; // orance
00544                             }
00545                             else if (H < 70)
00546                             {
00547                                 nColor = 2; // yellow
00548                             }
00549                             else if (H < 155)
00550                             {
00551                                 nColor = 3; // green
00552                             }
00553                             else if (H < 186)
00554                             {
00555                                 nColor = 4; // cyan
00556                             }
00557                             else if (H < 278)
00558                             {
00559                                 nColor = 5; // blue
00560                             }
00561                             else if (H < 330)
00562                             {
00563                                 nColor = 6; // purple
00564                             }
00565                             else
00566                             {
00567                                 nColor = 0; // red
00568                             }
00569                             
00570                             if (V >= 7) // SV plane is segmented into 5 regions
00571                             {
00572                                 nIndex = 2 + (S >= 5) + (S >= 8);
00573                             }
00574                             else
00575                             {
00576                                 nIndex = (S >= 7);
00577                             }
00578                             nIndex += 9 + 5 * nColor; // 9~43
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     //Core::Feature::Grid*  mGrid;
00633     int                   mRow;
00634     int                   mCol;
00635 
00636 };//class
00637 
00638 } // namespace Feature
00639 } // namespace Core
00640 } // namespace Impala
00641 
00642 #endif

Generated on Fri Mar 19 09:31:05 2010 for ImpalaSrc by  doxygen 1.5.1