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

ColorMomentsKoen.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Array_ColorMomentsKoen_h
00002 #define Impala_Core_Array_ColorMomentsKoen_h
00003 
00004 #include <vector>
00005 #include "Core/Array/Arrays.h"
00006 #include "Core/Array/ArraySet.h"
00007 #include "Core/Array/Rgb2Ooo.h"
00008 #include "Core/Array/Set.h"
00009 #include "Core/Array/PixSum.h"
00010 #include "Core/Array/Add.h"
00011 #include "Core/Array/Sub.h"
00012 #include "Core/Array/Div.h"
00013 #include "Core/Array/Mul.h"
00014 #include "Core/Array/Norm2.h"
00015 #include "Core/Array/Threshold.h"
00016 #include "Core/Array/PixStat.h"
00017 #include "Core/Array/PrintData.h"
00018 #include "Core/Array/ProjectRange.h"
00019 
00020 /*
00021 This code is a refactored version of ColorMoments.h (by Taylan)
00022 Changes:
00023 - made ColorMoments into a class, removing the need for static variables
00024 - allow retrieval of intermediate color moments, instead of only invariants
00025 - allow translations in the (X,Y) coordinates without changing the input array
00026 - changed linked list into an STL vector
00027 - returns STL vectors instead of Impala Arrays (24x1) for moments/invariants
00028 - Fixed an off-by-one error in the X,Y arrays (need to run from 1..n, starting 
00029   at 0 yields an 'ignored' row)
00030 - Fixed a memory leak when using order=0: X1 and Y1 got leaked
00031 - Channel ranges should be in 0..1, because ranges of 255*255*1 and 1*1*1 are 
00032   not comparable to 255*255*255, while in the 'ignore' cases (^0) all three 
00033   should be equal!
00034 - W() and H() were used instead of CW() and CH()!!! For images with a border,
00035   this can give strange results
00036 The usage of this code is different from Taylans; using both will result in name 
00037 clashes.
00038 */
00039 
00040 namespace Impala
00041 {
00042 namespace Core
00043 {
00044 namespace Array
00045 {
00046 
00047 class ColorMoments {
00048 
00049 public:
00050     int mShiftX;
00051     int mShiftY;
00052 
00053     ColorMoments() : mShiftX(0), mShiftY(0) {}
00054     
00055     
00056     void 
00057     SetCoordinateShift(int shiftX, int shiftY) 
00058     {
00059         /* by default, X and Y will count 0..w-1 and 0..h-1 
00060            This function adjusts the range: shiftX=1 -> 1..w */
00061         mShiftX = shiftX;
00062         mShiftY = shiftY;
00063     }
00064 
00065 
00066     void
00067     FillMomentCache(Array2dVec3Real64* rgb, int order, int degree, bool useBinaryMask=false, Array2dScalarReal64* binaryMask=0, bool blur=true, double sigma=10.0)
00068     {
00069         /* the binary mask should contain 0/1's only; it can be used to exclude
00070            certain pixels from rgb and should have the same size */
00071     
00072         /* clear the moment cache - just in case */
00073         mMomentCache.clear();
00074 
00075         Real64 TotalPixels = rgb->CW()*rgb->CH();
00076         if(useBinaryMask) {
00077             /* the total number of pixels is different */
00078             TotalPixels = PixSum(binaryMask);
00079         }
00080         
00081         ArraySet<Array2dScalarReal64>* X=new ArraySet<Array2dScalarReal64>(order+1);
00082         ArraySet<Array2dScalarReal64>* Y=new ArraySet<Array2dScalarReal64>(order+1);
00083         
00084         ArraySet<Array2dScalarReal64>* R=new ArraySet<Array2dScalarReal64>(degree+1);
00085         ArraySet<Array2dScalarReal64>* G=new ArraySet<Array2dScalarReal64>(degree+1);
00086         ArraySet<Array2dScalarReal64>* B=new ArraySet<Array2dScalarReal64>(degree+1);
00087         
00088         X->Array(0)=new Array2dScalarReal64(rgb->CW(),rgb->CH(),0,0);
00089         Y->Array(0)=new Array2dScalarReal64(rgb->CW(),rgb->CH(),0,0);
00090         R->Array(0)=new Array2dScalarReal64(rgb->CW(),rgb->CH(),0,0);
00091         G->Array(0)=new Array2dScalarReal64(rgb->CW(),rgb->CH(),0,0);
00092         B->Array(0)=new Array2dScalarReal64(rgb->CW(),rgb->CH(),0,0);
00093     
00094         //Oth order/degree values are all 1;
00095         SetVal(X->Array(0),1);
00096         SetVal(Y->Array(0),1);
00097         SetVal(R->Array(0),1);
00098         SetVal(G->Array(0),1);
00099         SetVal(B->Array(0),1);
00100     
00101         //1st order/degree values are same with corresponding vectors
00102         if(order > 0) {
00103             // only compute (and allocate) these if they are needed
00104             X->Array(1)=new Array2dScalarReal64(rgb->CW(),rgb->CH(),0,0);
00105             Y->Array(1)=new Array2dScalarReal64(rgb->CW(),rgb->CH(),0,0);
00106             for(int i=0;i<rgb->CW();i++) {
00107                 for(int j=0;j<rgb->CH();j++) {
00108                     X->Array(1)->SetValue(i+mShiftX+1,i,j);
00109                     Y->Array(1)->SetValue(j+mShiftY+1,i,j);
00110                 }
00111             }
00112         }
00113 
00114         ProjectRange(R->Array(1),rgb,1);
00115         ProjectRange(G->Array(1),rgb,2);
00116         ProjectRange(B->Array(1),rgb,3);
00117         
00118         if(blur){
00119             Array2dScalarReal64* tmp=0;
00120             RecGauss(tmp,R->Array(1),sigma,sigma,0,0,1);
00121             Set(R->Array(1),tmp);
00122             delete tmp;tmp=0;
00123             RecGauss(tmp,G->Array(1),sigma,sigma,0,0,1);
00124             Set(G->Array(1),tmp);
00125             delete tmp;tmp=0;
00126             RecGauss(tmp,B->Array(1),sigma,sigma,0,0,1);
00127             Set(B->Array(1),tmp);
00128             delete tmp;tmp=0;
00129         }
00130     
00131         for(int o=2;o<=order;o++){
00132             Mul(X->Array(o),X->Array(o-1),X->Array(1));
00133             Mul(Y->Array(o),Y->Array(o-1),Y->Array(1));
00134         }
00135         for(int d=2;d<=degree;d++){
00136             Mul(R->Array(d),R->Array(d-1),R->Array(1));
00137             Mul(G->Array(d),G->Array(d-1),G->Array(1));
00138             Mul(B->Array(d),B->Array(d-1),B->Array(1));
00139         }
00140         for(int o=0;o<=order;o++){
00141             for (int p=0;p<=o;p++){
00142                 for (int q=0;q<=o;q++){
00143                     if( p+q == o) {
00144                         for(int d=0;d<=degree;d++){
00145                             for(int r=0;r<=d;r++){
00146                                 for(int g=0;g<=d;g++){
00147                                     for(int b=0;b<=d;b++){
00148                                         if(r+g+b==d){
00149                                             Array2dScalarReal64* m = 0;
00150                                             Set(m,R->Array(r));
00151                                             if(g!=0)
00152                                                 Mul(m,m,G->Array(g));
00153                                             if(b!=0)
00154                                                 Mul(m,m,B->Array(b));
00155                                             if(p!=0)
00156                                                 Mul(m,m,X->Array(p));
00157                                             if(q!=0)
00158                                                 Mul(m,m,Y->Array(q));
00159                                             if(useBinaryMask) {
00160                                                 /* TotalPixels has been adapted above, now apply the mask */
00161                                                 Mul(m,m,binaryMask);
00162                                             }
00163                                             /*
00164                                             WriteRaw(R->Array(r), "r.raw", false);
00165                                             WriteRaw(G->Array(g), "g.raw", false);
00166                                             WriteRaw(B->Array(b), "b.raw", false);
00167                                             WriteRaw(X->Array(p), "x.raw", false);
00168                                             WriteRaw(Y->Array(q), "y.raw", false);
00169                                             WriteRaw(binaryMask, "binarymask.raw", false);
00170                                             WriteRaw(m, "m.raw", false);
00171                                             std::cout << rgb->CW() << " " << rgb->CH() << " "<< r << g << b << p << q << std::endl;
00172                                             std::cout << TotalPixels << " " << PixSum(m) << " " << std::endl; */
00173                                             Real64 moment = PixSum(m)/TotalPixels;
00174                                             //std::cout << moment << std::endl;
00175                                             delete m;
00176                                             mMomentCache.push_back(ColorMoment(p,q,r,g,b,moment));
00177                                         }
00178                                     }
00179                                 }
00180                             }
00181                         }
00182                     }
00183                 }
00184             }
00185         }
00186         for(int o=0;o<=order;o++){
00187             delete X->Array(o);
00188             delete Y->Array(o);
00189         }
00190         for(int d=0;d<=degree;d++){
00191             delete R->Array(d);
00192             delete G->Array(d);
00193             delete B->Array(d);
00194         }
00195         delete X,Y,R,G,B;
00196     }
00197 
00198 
00199     void
00200     GetMoments(std::vector<Real64>& moments, Array2dVec3UInt8* rgb,
00201                int order, int degree, bool useBinaryMask=false, Array2dScalarReal64* binaryMask=0, bool blur=false, double sigma=10.0)
00202     {
00203         Array2dVec3Real64* tmp = 0;
00204         // scale intensity to the range 0..1 instead of 0..255 so color moments
00205         // make sense!!! Using integer images is a *very* bad idea, because
00206         // your ranges are no longer comparable!
00207         MulVal(tmp, rgb, 1);         // first promote to real
00208         MulVal(tmp, tmp, 1 / 255.0); // then scale the range
00209         GetMoments(moments, tmp, order, degree, useBinaryMask, binaryMask, blur, sigma);
00210         delete tmp;
00211     }
00212 
00213 
00214     void
00215     GetMoments(std::vector<Real64>& moments, Array2dVec3Real64* rgb,
00216                int order, int degree, bool useBinaryMask=false, Array2dScalarReal64* binaryMask=0, bool blur=false, double sigma=10.0)
00217     {
00218         // fill the cache
00219         FillMomentCache(rgb, order, degree, useBinaryMask, binaryMask, blur, sigma);
00220         // dump the cache
00221         GetAllMoments(moments);
00222     }
00223 
00224     void
00225     GetInvariants(std::vector<Real64>& momentInvariants, Array2dVec3UInt8* rgb,
00226                bool useBinaryMask=false, Array2dScalarReal64* binaryMask=0, bool blur=false, double sigma=10.0)
00227     {
00228         Array2dVec3Real64* tmp = 0;
00229         // scale intensity to the range 0..1 instead of 0..255 so color moments
00230         // make sense!!! Using integer images is a *very* bad idea, because
00231         // your ranges are no longer comparable!
00232         MulVal(tmp, rgb, 1);         // first promote to real
00233         MulVal(tmp, tmp, 1 / 255.0); // then scale the range
00234         GetInvariants(momentInvariants, tmp, useBinaryMask, binaryMask, blur, sigma);
00235         delete tmp;
00236     }
00237 
00238     void
00239     GetInvariants(std::vector<Real64>& momentInvariants,Array2dVec3Real64* rgb,
00240                   bool useBinaryMask=false, Array2dScalarReal64* binaryMask=0, bool blur=false, double sigma=10.0)
00241     {
00242                 /* order=1, degree=2, otherwise invariants below cannot be computed */
00243         FillMomentCache(rgb, 1, 2, useBinaryMask, binaryMask, blur, sigma);
00244            
00245         momentInvariants.push_back(B02('R'));
00246         momentInvariants.push_back(B02('G'));
00247         momentInvariants.push_back(B02('B'));
00248         momentInvariants.push_back(C02("RG"));
00249         momentInvariants.push_back(C02("RB"));
00250         momentInvariants.push_back(C02("GB"));
00251         momentInvariants.push_back(C02tilde("RG"));
00252         momentInvariants.push_back(C02tilde("RB"));
00253         momentInvariants.push_back(C02tilde("GB"));
00254     
00255         momentInvariants.push_back(C11("RG"));
00256         momentInvariants.push_back(C11("RB"));
00257         momentInvariants.push_back(C11("GB"));
00258         momentInvariants.push_back(B12('R'));
00259         momentInvariants.push_back(B12('G'));
00260         momentInvariants.push_back(B12('B'));
00261         momentInvariants.push_back(C12_1("RG"));
00262         momentInvariants.push_back(C12_1("RB"));
00263         momentInvariants.push_back(C12_1("GB"));
00264         momentInvariants.push_back(C12_2("RG"));
00265         momentInvariants.push_back(C12_2("RB"));
00266         momentInvariants.push_back(C12_2("GB"));
00267         
00268         momentInvariants.push_back(C12_3("RG"));
00269         momentInvariants.push_back(C12_3("GB"));
00270         momentInvariants.push_back(C12_4("RB"));
00271     }
00272 
00273 private:
00274 
00275     class ColorMoment {
00276     public:
00277     
00278         ColorMoment(int x, int y, int r, int g, int b, Real64 val) 
00279                    : p(x), q(y), a(r), b(g), c(b), value(val) {}
00280     
00281         int p;  //power of x |
00282         int q;  //power of y |=>these two give the order of the Moment
00283     
00284         int a;  //power of R |
00285         int b;  //power of G |
00286         int c;  //power of B |=>these 3 give the degree of the Moment
00287     
00288         Real64 value;
00289     };
00290     
00291     std::vector<ColorMoment> mMomentCache;
00292 
00293     void GetAllMoments(std::vector<Real64>& output) {
00294         for(int i = 0; i < mMomentCache.size(); i++) {
00295             ColorMoment& m = mMomentCache[i];
00296             output.push_back(m.value);
00297         }   
00298     }
00299 
00300     Real64 GetMoment(int p, int q, int a, int b, int c)
00301     {
00302         for(int i = 0; i < mMomentCache.size(); i++) {
00303             ColorMoment& out = mMomentCache[i];
00304             if ((out.p == p)&&
00305                 (out.q == q)&&
00306                 (out.a == a)&&
00307                 (out.b == b)&&
00308                 (out.c == c))
00309                 return out.value;
00310         }   
00311         return 0;
00312     }
00313 
00314     /*** definitions of the moment invariants ***/
00315 
00316     inline Real64 SB(int p, int q, char band, int degree){
00317         if(band=='R')
00318             return GetMoment(p,q,degree,0,0);
00319         if(band=='G')
00320             return GetMoment(p,q,0,degree,0);
00321         if(band=='B')
00322             return GetMoment(p,q,0,0,degree);
00323         return 0;
00324     }
00325     
00326     inline Real64 DB(int p, int q, std::string band, int degree1,int degree2){
00327         if(band=="RG") //RG
00328             return GetMoment(p,q,degree1,degree2,0);
00329         if(band=="RB") //RB
00330             return GetMoment(p,q,degree1,0,degree2);
00331         if(band=="GB") //GB
00332             return GetMoment(p,q,0,degree1,degree2);
00333         return 0;
00334     }
00335     
00336     Real64 B02(char band){
00337         return (SB(0 ,0,band,0)*SB(0,0,band,2))/(SB(0,0,band,1)*SB(0,0,band,1));
00338     }
00339     
00340     Real64 B12(char band){
00341         Real64 res = 
00342         SB(1 ,0,band,1)*SB(0,1,band,2)*SB(0,0,band,0)+
00343         SB(1 ,0,band,2)*SB(0,1,band,0)*SB(0,0,band,1)+
00344         SB(1,0,band,0)*SB(0,1,band,1)*SB(0,0,band,2)-
00345         SB(1,0,band,0)*SB(0,1,band,2)*SB(0,0,band,1)-
00346         SB(1,0,band,1)*SB(0,1,band,0)*SB(0,0,band,2)-
00347         SB(1,0,band,2)*SB(0,1,band,1)*SB(0,0,band,0);
00348     
00349         res/=(SB(0,0,band,2)*SB(0,0,band,1)*SB(0,0,band,0));
00350         return res;
00351     }
00352     
00353     Real64 C02(std::string band){
00354         return (DB(0,0,band,1,1)*DB(0,0,band,0,0))/(DB(0,0,band,0,1)*DB(0,0,band,1,0));
00355     }
00356     
00357     Real64 C02tilde(std::string band){
00358         return (DB(0,0,band,2,0)*DB(0,0,band,0,2))/(DB(0,0,band,1,1)*DB(0,0,band,1,1));
00359     }
00360     
00361     Real64 C11(std::string band){
00362         return((DB(1,0,band,1,0)*DB(0,1,band,0,1)*DB(0,0,band,0,0) +
00363                 DB(1,0,band,0,1)*DB(0,1,band,0,0)*DB(0,0,band,1,0) +
00364                 DB(1,0,band,0,0)*DB(0,1,band,1,0)*DB(0,0,band,0,1) - 
00365                 DB(1,0,band,0,0)*DB(0,1,band,0,1)*DB(0,0,band,1,0) - 
00366                 DB(1,0,band,1,0)*DB(0,1,band,0,0)*DB(0,0,band,0,1) -
00367                 DB(1,0,band,0,1)*DB(0,1,band,1,0)*DB(0,0,band,0,0) )/
00368                (DB(0,0,band,1,0)*DB(0,0,band,0,1)*DB(0,0,band,0,0)));
00369     }
00370     Real64 C12_1(std::string band){
00371         return((DB(1,0,band,1,0)*DB(0,1,band,1,1)*DB(0,0,band,0,0) +
00372                 DB(1,0,band,1,1)*DB(0,1,band,0,0)*DB(0,0,band,1,0) +
00373                 DB(1,0,band,0,0)*DB(0,1,band,1,0)*DB(0,0,band,1,1) - 
00374                 DB(1,0,band,0,0)*DB(0,1,band,1,1)*DB(0,0,band,1,0) - 
00375                 DB(1,0,band,1,0)*DB(0,1,band,0,0)*DB(0,0,band,1,1) -
00376                 DB(1,0,band,1,1)*DB(0,1,band,1,0)*DB(0,0,band,0,0) )/
00377                (DB(0,0,band,1,1)*DB(0,0,band,1,0)*DB(0,0,band,0,0)));
00378     
00379     }
00380     Real64 C12_2(std::string band){
00381         return((DB(1,0,band,0,1)*DB(0,1,band,1,1)*DB(0,0,band,0,0) +
00382                 DB(1,0,band,1,1)*DB(0,1,band,0,0)*DB(0,0,band,0,1) +
00383                 DB(1,0,band,0,0)*DB(0,1,band,0,1)*DB(0,0,band,1,1) - 
00384                 DB(1,0,band,0,0)*DB(0,1,band,1,1)*DB(0,0,band,0,1) - 
00385                 DB(1,0,band,0,1)*DB(0,1,band,0,0)*DB(0,0,band,1,1) -
00386                 DB(1,0,band,1,1)*DB(0,1,band,0,1)*DB(0,0,band,0,0) )/
00387                (DB(0,0,band,1,1)*DB(0,0,band,0,1)*DB(0,0,band,0,0)));
00388     }
00389     Real64 C12_3(std::string band){
00390         return((DB(1,0,band,1,0)*DB(0,1,band,0,2)*DB(0,0,band,0,0) +
00391                 DB(1,0,band,0,2)*DB(0,1,band,0,0)*DB(0,0,band,1,0) +
00392                 DB(1,0,band,0,0)*DB(0,1,band,1,0)*DB(0,0,band,0,2) - 
00393                 DB(1,0,band,0,0)*DB(0,1,band,0,2)*DB(0,0,band,1,0) - 
00394                 DB(1,0,band,1,0)*DB(0,1,band,0,0)*DB(0,0,band,0,2) -
00395                 DB(1,0,band,0,2)*DB(0,1,band,1,0)*DB(0,0,band,0,0) )/
00396                (DB(0,0,band,1,0)*DB(0,0,band,0,2)*DB(0,0,band,0,0)));
00397     }
00398     
00399     Real64 C12_4(std::string band){
00400         return((DB(1,0,band,2,0)*DB(0,1,band,0,1)*DB(0,0,band,0,0) +
00401                 DB(1,0,band,0,1)*DB(0,1,band,0,0)*DB(0,0,band,2,0) +
00402                 DB(1,0,band,0,0)*DB(0,1,band,2,0)*DB(0,0,band,0,1) - 
00403                 DB(1,0,band,0,0)*DB(0,1,band,0,1)*DB(0,0,band,2,0) - 
00404                 DB(1,0,band,2,0)*DB(0,1,band,0,0)*DB(0,0,band,0,1) -
00405                 DB(1,0,band,0,1)*DB(0,1,band,2,0)*DB(0,0,band,0,0) )/
00406                (DB(0,0,band,2,0)*DB(0,0,band,0,1)*DB(0,0,band,0,0)));
00407     }
00408 
00409 };
00410 
00411 } // namespace Array
00412 } // namespace Core
00413 } // namespace Impala
00414 
00415 #endif

Generated on Fri Mar 19 09:30:44 2010 for ImpalaSrc by  doxygen 1.5.1