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

Generated on Thu Jan 13 09:04:26 2011 for ImpalaSrc by  doxygen 1.5.1