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

RegionDescriptor.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Feature_RegionDescriptor_h
00002 #define Impala_Core_Feature_RegionDescriptor_h
00003 
00004 #include "Core/Array/MakeCircle.h"
00005 #include "Core/Array/ProjectRange.h"
00006 #include "Core/Array/Resample.h"
00007 #include "Core/Histogram/MakeHistogram1d.h"
00008 #include "Core/Histogram/Histogram1dSet.h"
00009 #include "Core/Array/Rgb2Ooo.h"
00010 #include "Core/Array/RGB2rg.h"
00011 #include "Core/Array/MakeFromData.h"
00012 #include "Core/Array/ColorMomentsKoen.h"
00013 #include "Core/Array/Atan2.h"
00014 #include "Core/Array/Sqrt.h"
00015 
00016 #include "Core/Vector/VectorSet.h"
00017 #include "Core/Histogram/MakeHistogram1dSet.h"
00018 
00019 namespace Impala
00020 {
00021 namespace Core
00022 {
00023 namespace Feature
00024 {
00025 
00026 
00027 Array::Array2dScalarReal64*
00028 CreateCircleMask(int patchSize) 
00029 {
00030     using namespace Impala::Core::Array;
00031     Array2dScalarReal64* circleMask = 0;
00032     circleMask = ArrayCreate<Array2dScalarReal64>(patchSize, patchSize);
00033     MakeCircle(circleMask, patchSize / 2, patchSize / 2, Real64(patchSize) / 2.0, 1, 0);
00034     return circleMask;
00035 }
00036 
00037 
00038 void
00039 ComputeRegionDescriptor(std::vector<Real64>& vec, Array::Array2dVec3UInt8* src,
00040                         String descriptor, bool useCircularMask, int srcCenterX,
00041                         int srcCenterY)
00042 {
00043     using namespace Impala::Core::Array;
00044     using namespace Impala::Core::Histogram;
00045 
00046     /* note: ensure that vec is empty when you call this function */
00047     //WriteRaw(src, String("src.raw"), false);
00048 
00049     /* certain descriptors can only be computed over square images */
00050     bool imgIsSquare = (src->CW() == src->CH());
00051     int binCount = 15;
00052     Real64 uniformPatchSize = 61;           // when making the src uniformly sized; resize to 61x61
00053 
00054     /* support bin count changing */
00055     CmdOptions& options = CmdOptions::GetInstance();
00056     binCount = options.GetInt("descriptorBinCount");
00057 
00058     Array2dScalarReal64* circleMask = 0;
00059     if(useCircularMask) {
00060         if(!imgIsSquare) {
00061             std::cerr << "[ERROR] Using circularMask on a non-square source!" << std::endl;
00062             throw "Using circularMask on a non-square source!";
00063         }
00064         circleMask = CreateCircleMask(src->CW());
00065     }
00066     
00067     if(descriptor == "opponenthistogram") {
00068         /***** OPPONENT COLOR HISTOGRAM *****/
00069         vec.reserve(binCount * 3);
00070     
00071         // color conversion
00072         Array2dVec3Real64* srcOpponent = 0;
00073         Rgb2Ooo(srcOpponent, src);
00074         //WriteRaw(srcOpponent, String("srcopp.raw"), false);
00075         
00076         double lower[3] = {0, -70, -70};
00077         double upper[3] = {270, 70, 70};
00078 
00079         if(useCircularMask) {
00080             AddVal(circleMask, circleMask, -1);
00081             MulVal(circleMask, circleMask, 1000);   // now it is 0 in the circle and -1000 elsewhere
00082         }
00083 
00084         for (int d=1 ; d<=src->ElemSize() ; d++)
00085         {
00086             Array2dScalarReal64* comp = 0;
00087             ProjectRange(comp, srcOpponent, d);
00088             
00089             if(useCircularMask) {
00090                 /* add them together, making values outside the circle very negative (i.e. an outlier) */
00091                 Add(comp, comp, circleMask);
00092                 //WriteRaw(comp, String("x.raw"), false);
00093             }
00094             
00095             Histogram1dTem<Real64> hist(lower[d-1], upper[d-1], binCount, 0);
00096             MakeHistogram1d(&hist, comp);
00097             hist.Normalize();
00098             if(hist.TotalWeight() == 0) {
00099                 /* debug code */
00100                 hist.Dump(true);
00101                 std::cout << "[WARNING] Opponent color histogram 100% outliers: " << srcCenterX << " " << srcCenterY << std::endl;
00102                 WriteRaw(comp, String("outlier.raw"), &Util::Database::GetInstance(), false);
00103             }
00104             delete comp;
00105             for(int i = 0; i < hist.Size(); i++) {
00106                 vec.push_back(hist.Elem(i));
00107             }
00108         }
00109         delete srcOpponent;
00110     } else if(descriptor == "nrghistogram") {
00111         /***** rgb HISTOGRAM (normalized rgb) *****/
00112         vec.reserve(binCount * 2);
00113 
00114         // color conversion
00115         Array2dVec3Real64* src_rg = 0;
00116         RGB2rg(src_rg, src);
00117     
00118         double lower[3] = {0, 0, 0};
00119         double upper[3] = {1, 1, 1};
00120 
00121         if(useCircularMask) {
00122             AddVal(circleMask, circleMask, -1);
00123             MulVal(circleMask, circleMask, 1000);   // now it is 0 in the circle and -1000 elsewhere
00124         }
00125 
00126         for (int d=1 ; d<=2 ; d++)
00127         {
00128             Array2dScalarReal64* comp = 0;
00129             ProjectRange(comp, src_rg, d);
00130             
00131             if(useCircularMask) {
00132                 /* add them together, making values outside the circle very negative (i.e. an outlier) */
00133                 Add(comp, comp, circleMask);
00134                 //WriteRaw(comp, String("x.raw"), false);
00135             }
00136             
00137             Histogram1dTem<Real64> hist(lower[d-1], upper[d-1], binCount, 0);
00138             MakeHistogram1d(&hist, comp);
00139             hist.Normalize();
00140             //hist.Dump(true);
00141             //std::cout << comp->CW() << std::endl;
00142             delete comp;
00143             for(int i = 0; i < hist.Size(); i++) {
00144                 vec.push_back(hist.Elem(i));
00145             }
00146         }
00147         delete src_rg;
00148     } else if(descriptor == "rgbhistogram") {
00149         /***** RGB HISTOGRAM *****/
00150         vec.reserve(binCount * 3);
00151     
00152         double lower[3] = {0, 0, 0};
00153         double upper[3] = {256, 256, 256};
00154 
00155         if(useCircularMask) {
00156             AddVal(circleMask, circleMask, -1);
00157             MulVal(circleMask, circleMask, 1000);   // now it is 0 in the circle and -1000 elsewhere
00158         }
00159 
00160         for (int d=1 ; d<=src->ElemSize() ; d++)
00161         {
00162             Array2dScalarReal64* comp = 0;
00163             ProjectRange(comp, src, d);
00164             
00165             if(useCircularMask) {
00166                 /* add them together, making values outside the circle very negative (i.e. an outlier) */
00167                 Add(comp, comp, circleMask);
00168                 //WriteRaw(comp, String("x.raw"), false);
00169             }
00170             
00171             Histogram1dTem<Real64> hist(lower[d-1], upper[d-1], binCount, 0);
00172             MakeHistogram1d(&hist, comp);
00173             hist.Normalize();
00174             //hist.Dump(true);
00175             //std::cout << comp->CW() << std::endl;
00176             delete comp;
00177             for(int i = 0; i < hist.Size(); i++) {
00178                 vec.push_back(hist.Elem(i));
00179             }
00180         }
00181     } else if(descriptor == "transformedcolorhistogram") {
00182         /***** TRANSFORMED RGB HISTOGRAM *****/
00183         vec.reserve(binCount * 3);
00184     
00185         double lower[3] = {-2, -2, -2};
00186         double upper[3] = { 2,  2,  2};
00187 
00188         for (int d=1 ; d<=src->ElemSize() ; d++)
00189         {
00190             Array2dScalarReal64* comp = 0;
00191             ProjectRange(comp, src, d);
00192             
00193             Real64 pixelCount = comp->CW() * comp->CH();
00194             if(useCircularMask) {
00195                 /* make values outside the circle zero */
00196                 Mul(comp, comp, circleMask);
00197                 pixelCount = PixSum(circleMask);
00198             }
00199 
00200             Real64 mu = PixSum(comp) / pixelCount;
00201             AddVal(comp, comp, -mu);
00202             if(useCircularMask) {
00203                 /* make values outside the circle zero */
00204                 Mul(comp, comp, circleMask);
00205             }
00206             //std::cout << "0-mean: " << mu << " " << PixSum(comp) << " " << PixSum(comp) / pixelCount << std::endl;
00207 
00208             Array2dScalarReal64* stddev = 0;
00209             Mul(stddev, comp, comp);    // square it -> (x - mu)^2
00210             if(useCircularMask) {
00211                 /* make values outside the circle zero */
00212                 Mul(stddev, stddev, circleMask);
00213             }
00214             Real64 standardDeviation = sqrt(PixSum(stddev) / pixelCount);
00215             MulVal(comp, comp, 1.0 / standardDeviation);
00216             //std::cout << PixSum(comp) / pixelCount << std::endl;
00217             
00218             Histogram1dTem<Real64> hist(lower[d-1], upper[d-1], binCount, 0);
00219             MakeHistogram1d(&hist, comp);
00220             hist.Normalize();
00221             //hist.Dump(true);
00222             delete comp;
00223             delete stddev;
00224             for(int i = 0; i < hist.Size(); i++) {
00225                 vec.push_back(hist.Elem(i));
00226             }
00227         }
00228 //    } else if(descriptor == "nu-colormoments") {
00229 //        /***** non-uniform COLOR MOMENTS *****/
00230 //        ColorMoments cm;
00231 //        cm.GetMoments(vec, src, 0, 2, useCircularMask, circleMask, false);
00232 //    } else if(descriptor == "nu-spatialcolormoments") {
00233 //        /***** non-uniform SPATIAL COLOR MOMENTS *****/
00234 //        ColorMoments cm;
00235 //        cm.GetMoments(vec, src, 1, 2, useCircularMask, circleMask, false);
00236 //    } else if(descriptor == "nupv-colormoments") {
00237 //        /***** non-uniform position-variant COLOR MOMENTS *****/
00238 //        ColorMoments cm;
00239 //        cm.SetCoordinateShift(srcCenterX, srcCenterY);
00240 //        cm.GetMoments(vec, src, 0, 2, useCircularMask, circleMask, false);
00241 //    } else if(descriptor == "nupv-spatialcolormoments") {
00242 //        /***** non-uniform position-variant SPATIAL COLOR MOMENTS *****/
00243 //        ColorMoments cm;
00244 //        cm.SetCoordinateShift(srcCenterX, srcCenterY);
00245 //        cm.GetMoments(vec, src, 1, 2, useCircularMask, circleMask, false);
00246 //    } else if(descriptor == "colormoments") {
00247 //        /***** COLOR MOMENTS *****/
00248 //        Array2dVec3UInt8* uniformSrc = 0;
00249 //        Resample(uniformSrc, src, uniformPatchSize, uniformPatchSize);
00250 //        if(useCircularMask) delete circleMask;
00251 //        circleMask = CreateCircleMask(uniformSrc->CW());
00252 //        
00253 //        ColorMoments cm;
00254 //        cm.GetMoments(vec, uniformSrc, 0, 2, useCircularMask, circleMask, false);
00255 //        delete uniformSrc;
00256     } else if(descriptor == "colormoments") {
00257         /***** SPATIAL COLOR MOMENTS *****/
00258         Array2dVec3UInt8* uniformSrc = 0;
00259         Resample(uniformSrc, src, uniformPatchSize, uniformPatchSize);
00260         if(useCircularMask) delete circleMask;
00261         circleMask = CreateCircleMask(uniformSrc->CW());
00262 
00263         ColorMoments cm;
00264         cm.GetMoments(vec, uniformSrc, 1, 2, useCircularMask, circleMask, false);
00265         delete uniformSrc;
00266 //    } else if(descriptor == "spatialcolormoments3") {
00267 //        /***** SPATIAL COLOR MOMENTS up to degree 3 *****/
00268 //        Array2dVec3UInt8* uniformSrc = 0;
00269 //        Resample(uniformSrc, src, uniformPatchSize, uniformPatchSize);
00270 //        if(useCircularMask) delete circleMask;
00271 //        circleMask = CreateCircleMask(uniformSrc->CW());
00272 //
00273 //        ColorMoments cm;
00274 //        cm.GetMoments(vec, uniformSrc, 1, 3, useCircularMask, circleMask, false);
00275 //        delete uniformSrc;
00276     } else if(descriptor == "colormomentinvariants") {
00277         /***** COLOR MOMENT INVARIANTS *****/
00278         Array2dVec3UInt8* uniformSrc = 0;
00279         Resample(uniformSrc, src, uniformPatchSize, uniformPatchSize);
00280         if(useCircularMask) delete circleMask;
00281         circleMask = CreateCircleMask(uniformSrc->CW());
00282 
00283         ColorMoments cm;
00284         cm.GetInvariants(vec, uniformSrc, useCircularMask, circleMask, false);
00285         delete uniformSrc;
00286     } else if(descriptor == "huehistogram") {
00287         /***** HUE DESCRIPTOR *****/
00288         /* by Joost van de Weijer, ECCV2006. Not included: Gaussian weighting mask */
00289 
00290         // default to the setting used by the paper
00291         if(binCount == 15) binCount = 37;
00292         
00293         //H=atan2((patches_R+patches_G-2*patches_B),sqrt(3)*(patches_R-patches_G))+pi;
00294         Array2dScalarReal64* H = 0;
00295 
00296         Array2dScalarReal64* R = 0;
00297         Array2dScalarReal64* G = 0;
00298         Array2dScalarReal64* B = 0;
00299         ProjectRange(R, src, 1);
00300         ProjectRange(G, src, 2);
00301         ProjectRange(B, src, 3);
00302 
00303         Array2dScalarReal64* X = 0;
00304         Add(X, R, G);
00305         MulVal(B, B, -1);
00306         Add(X, X, B);
00307         Add(X, X, B);
00308         Array2dScalarReal64* Y = 0;
00309         MulVal(G, G, -1);
00310         Add(Y, R, G);
00311         MulVal(Y, Y, sqrt(3.0));
00312         Atan2(H, X, Y);
00313         Real64 myPI = 3.1415927;
00314         AddVal(H, H, myPI);
00315         delete X; X = 0;
00316         delete Y; Y = 0;
00317 
00318         /* reset to correct values */
00319         ProjectRange(R, src, 1);
00320         ProjectRange(G, src, 2);
00321         ProjectRange(B, src, 3);
00322         
00323         //saturation=sqrt(2/3*(patches_R.^2+patches_G.^2+patches_B.^2-patches_R.*(patches_G+patches_B)-patches_G.*patches_B)+0.01);
00324         Array2dScalarReal64* Saturation = 0;
00325         // patches_R.^2+patches_G.^2+patches_B.^2
00326         Array2dScalarReal64* R2 = 0;
00327         Array2dScalarReal64* G2 = 0;
00328         Array2dScalarReal64* B2 = 0;
00329         Mul(R2, R, R);
00330         Mul(G2, G, G);
00331         Mul(B2, B, B);
00332         Add(X, R2, G2);
00333         Add(X, X, B2);
00334         delete R2; delete G2; delete B2;
00335         
00336         // previous-patches_R.*(patches_G+patches_B)
00337         Add(Y, G, B);
00338         Mul(Y, R, Y);
00339         MulVal(Y, Y, -1);
00340         Add(X, X, Y);
00341         
00342         // -patches_G.*patches_B
00343         Mul(Y, G, B);
00344         MulVal(Y, Y, -1);
00345         Add(X, X, Y);
00346         
00347         MulVal(X, X, 2.0 / 3.0);
00348         AddVal(X, X, 0.01);
00349         Sqrt(Saturation, X);
00350 
00351         delete R; delete G; delete B; delete X; delete Y;
00352 
00353         Histogram1dTem<Real64> hist(0, 2 * myPI, binCount, 0);
00354         if(useCircularMask) {
00355             Mul(Saturation, Saturation, circleMask);   // everything not in the mask will not be included
00356         }
00357         MakeHistogram1d(&hist, H, Saturation);
00358         hist.Normalize();
00359         //hist.Dump(true);
00360         for(int i = 0; i < hist.Size(); i++) {
00361             vec.push_back(hist.Elem(i));
00362         }
00363         delete H; delete Saturation;
00364         
00365     } else {
00366         std::cerr << "[ERROR] Invalid descriptor name: " << descriptor << std::endl;
00367         throw "Invalid descriptor name";
00368     }
00369     if(circleMask) delete circleMask;
00370 }
00371 
00372 
00373 void
00374 MakePatch(Array::Array2dVec3UInt8*& patch, Array::Array2dVec3UInt8* img, int x,
00375           int y, int pixelsAround)
00376 {
00377     Geometry::Rectangle regionRect(x - pixelsAround, y - pixelsAround,
00378                                    x + pixelsAround, y + pixelsAround);
00379     if((regionRect.mLeft   < - img->BW()) || 
00380        (regionRect.mTop    < - img->BH()) ||
00381        (regionRect.mRight  >= img->CW() + img->BW()) ||
00382        (regionRect.mBottom >= img->CH() + img->BH()) ) {
00383        
00384         //std::cerr << "[WARNING] Decreased pixelsAround to 120 in MakePatch to avoid going beyond borders of image, value was " << pixelsAround << std::endl;
00385         
00386         pixelsAround = 120;    // this should always work
00387         regionRect.mLeft = x - pixelsAround;
00388         regionRect.mTop = y - pixelsAround;
00389         regionRect.mRight = x + pixelsAround;
00390         regionRect.mBottom = y + pixelsAround;
00391         /*
00392         std::cerr << "[WARNING] Segfault possible due to too small border in MakePatch!" << std::endl;
00393         std::cerr << regionRect.mLeft   <<" "<< - img->BW() <<" "<< 
00394                      regionRect.mTop    <<" "<< - img->BH() <<" "<<
00395                      regionRect.mRight  <<" "<< img->CW() + img->BW() <<" "<<
00396                      regionRect.mBottom <<" "<< img->CH() + img->BH() << std::endl;
00397         std::cerr << "x=" << x << " y=" << y << " size=" << pixelsAround << std::endl; */
00398     }
00399     patch = MakeRoi(img, regionRect);
00400 }
00401 
00402 
00403 void
00404 CalculateRegionDescriptors(Array::Array2dVec3UInt8* inputNoBorder,
00405                            Geometry::InterestPointList& pointList,
00406                            String descriptor)
00407 {
00408     using namespace Impala::Core::Array;
00409     using namespace Impala::Core::Geometry;
00410 
00411     // start of descriptor computation code
00412     Real64 scaleMultiplier = 10;     // used to be 4
00413     Real64 extraBorder = 120;
00414     
00415     Array2dVec3UInt8* input =
00416         ArrayCreate<Array2dVec3UInt8>(inputNoBorder->CW(), inputNoBorder->CH(), extraBorder, extraBorder);
00417     MakeFromData2<Array2dVec3UInt8,Array2dVec3UInt8>(input, inputNoBorder);
00418     /* now mirror the data into the border */
00419     Pattern::FuncBorderMirror2d(input, extraBorder, extraBorder);
00420 
00421     /* support bin count changing */
00422     CmdOptions& options = CmdOptions::GetInstance();
00423     if(options.GetInt("descriptorPreSmoothing") != 0) {
00424         /* pre-smooth the input */
00425         Real64 sigmaSmooth = 1.0;
00426 
00427         std::vector<Array2dScalarReal64*> resList;
00428         for (int d=1 ; d<=input->ElemSize() ; d++)
00429         {
00430             Array2dScalarReal64* comp = 0;
00431             ProjectRange(comp, input, d);
00432             GaussDerivative(comp, comp, sigmaSmooth, 0, 0, 3.0);
00433             resList.push_back(comp);
00434             delete comp;
00435         }
00436         delete input;
00437         input = 0;
00438         MakeFrom3Images(input, resList[0], resList[1], resList[2]);
00439         ArrayListDelete(&resList);
00440     }
00441 
00442     //ArraySystem::Instance().MarkMemoryUsage(true);          // DEBUG
00443     for(InterestPointList::iterator iter = pointList.begin(); iter != pointList.end(); iter++)
00444     {
00445         // make it a reference, because we want to modify it in-place
00446         InterestPoint* point = *iter;
00447         
00448         if(point->geometryType() == "CircleZ") {
00449             /* cast to a circle */
00450             InterestCircle* circle(dynamic_cast<InterestCircle*>(point));
00451 
00452             /* this code makes the (very strong) assumption that (X,Y) are integers, which is true in the interest point datastructure */
00453             int pixelsAround = floor(circle->mScale * scaleMultiplier + 0.5);
00454             Array2dVec3UInt8* patch = 0;
00455             int x = floor(circle->mX + 0.5);
00456             int y = floor(circle->mY + 0.5);
00457                     
00458             MakePatch(patch, input, x, y, pixelsAround);
00459             
00460             /* compute a descriptor over the patch */
00461             // do not clear it first, then I cannot concatenate descriptors!
00462             //point->mDescriptor.clear();
00463 
00464             //std::cout << "--new point with scale: " << circle->mScale << std::endl;
00465             ComputeRegionDescriptor(circle->mDescriptor, patch, descriptor, true, x, y);
00466 
00467             delete patch;
00468         } else if(point->geometryType() == "RectangleZ") {
00469             /* cast to a rectangle */
00470             InterestRectangleZ* rectangle(dynamic_cast<InterestRectangleZ*>(point));
00471 
00472             /* this code makes the (very strong) assumption that (X,Y) are integers, which is true in the interest point datastructure */
00473             Array2dVec3UInt8* patch = MakeRoi(input, rectangle->GetRect());
00474                    
00475             /* compute a descriptor over the patch; do *not* use a circular mask */
00476             // do not clear it first, then I cannot concatenate descriptors!
00477             //point->mDescriptor.clear();
00478 
00479             ComputeRegionDescriptor(rectangle->mDescriptor, patch, descriptor, false, rectangle->mX, rectangle->mY);
00480 
00481             delete patch;
00482         } else {
00483             throw "[CalculateDescriptors] Unknown geometry type: " + point->geometryType();
00484         }
00485         //ArraySystem::Instance().MemoryUsageSinceMark(true);     // DEBUG
00486     }
00487     delete input;
00488 }
00489 
00490 } // namespace Feature
00491 } // namespace Core
00492 } // namespace Impala
00493 
00494 #endif

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