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     
00051     
00052 
00053     
00054     bool imgIsSquare = (src->CW() == src->CH());
00055     int binCount = 15;
00056     Real64 uniformPatchSize = 61;           
00057 
00058     
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         
00073         vec.reserve(binCount * 3);
00074     
00075         
00076         Array2dVec3Real64* srcOpponent = 0;
00077         Rgb2Ooo(srcOpponent, src);
00078         
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);   
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                 
00095                 Add(comp, comp, circleMask);
00096                 
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                 
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         
00117         vec.reserve(binCount * 2);
00118 
00119         
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);   
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                 
00138                 Add(comp, comp, circleMask);
00139                 
00140             }
00141             
00142             Histogram1dTem<Real64> hist(lower[d-1], upper[d-1], binCount, 0);
00143             MakeHistogram1d(&hist, comp);
00144             hist.Normalize();
00145             
00146             
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         
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);   
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                 
00172                 Add(comp, comp, circleMask);
00173                 
00174             }
00175             
00176             Histogram1dTem<Real64> hist(lower[d-1], upper[d-1], binCount, 0);
00177             MakeHistogram1d(&hist, comp);
00178             hist.Normalize();
00179             
00180             
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         
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                 
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                 
00209                 Mul(comp, comp, circleMask);
00210             }
00211             
00212 
00213             Array2dScalarReal64* stddev = 0;
00214             Mul(stddev, comp, comp);    
00215             if(useCircularMask) {
00216                 
00217                 Mul(stddev, stddev, circleMask);
00218             }
00219             Real64 standardDeviation = sqrt(PixSum(stddev) / pixelCount);
00220             MulVal(comp, comp, 1.0 / standardDeviation);
00221             
00222             
00223             Histogram1dTem<Real64> hist(lower[d-1], upper[d-1], binCount, 0);
00224             MakeHistogram1d(&hist, comp);
00225             hist.Normalize();
00226             
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 
00234 
00235 
00236 
00237 
00238 
00239 
00240 
00241 
00242 
00243 
00244 
00245 
00246 
00247 
00248 
00249 
00250 
00251 
00252 
00253 
00254 
00255 
00256 
00257 
00258 
00259 
00260 
00261     } else if(descriptor == "colormoments") {
00262         
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 
00272 
00273 
00274 
00275 
00276 
00277 
00278 
00279 
00280 
00281     } else if(descriptor == "colormomentinvariants") {
00282         
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         
00293         
00294 
00295         
00296         if(binCount == 15) binCount = 37;
00297         
00298         
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         
00324         ProjectRange(R, src, 1);
00325         ProjectRange(G, src, 2);
00326         ProjectRange(B, src, 3);
00327         
00328         
00329         Array2dScalarReal64* Saturation = 0;
00330         
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         
00342         Add(Y, G, B);
00343         Mul(Y, R, Y);
00344         MulVal(Y, Y, -1);
00345         Add(X, X, Y);
00346         
00347         
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);   
00361         }
00362         MakeHistogram1d(&hist, H, Saturation);
00363         hist.Normalize();
00364         
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         
00390         
00391         pixelsAround = 120;    
00392         regionRect.mLeft = x - pixelsAround;
00393         regionRect.mTop = y - pixelsAround;
00394         regionRect.mRight = x + pixelsAround;
00395         regionRect.mBottom = y + pixelsAround;
00396         
00397 
00398 
00399 
00400 
00401 
00402 
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     
00417     Real64 scaleMultiplier = 10;     
00418     Real64 extraBorder = 120;
00419     
00420     Array2dVec3UInt8* input =
00421         ArrayCreate<Array2dVec3UInt8>(inputNoBorder->CW(), inputNoBorder->CH(), extraBorder, extraBorder);
00422     MakeFromData2<Array2dVec3UInt8,Array2dVec3UInt8>(input, inputNoBorder);
00423     
00424     Pattern::FuncBorderMirror2d(input, extraBorder, extraBorder);
00425 
00426     
00427     CmdOptions& options = CmdOptions::GetInstance();
00428     if(options.GetInt("descriptorPreSmoothing") != 0) {
00429         
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     
00448     std::vector<Real64> tmpDescriptor;
00449     for(int i = 0; i < pointData->Size(); i++)
00450     {
00451         
00452 
00453         
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         
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 
00476 
00477 
00478 
00479 
00480 
00481 
00482 
00483 
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00491 
00492         
00493     }
00494     delete input;
00495 }
00496 
00497 } 
00498 } 
00499 } 
00500 
00501 #endif