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
00047
00048
00049
00050 bool imgIsSquare = (src->CW() == src->CH());
00051 int binCount = 15;
00052 Real64 uniformPatchSize = 61;
00053
00054
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
00069 vec.reserve(binCount * 3);
00070
00071
00072 Array2dVec3Real64* srcOpponent = 0;
00073 Rgb2Ooo(srcOpponent, src);
00074
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);
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
00091 Add(comp, comp, circleMask);
00092
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
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
00112 vec.reserve(binCount * 2);
00113
00114
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);
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
00133 Add(comp, comp, circleMask);
00134
00135 }
00136
00137 Histogram1dTem<Real64> hist(lower[d-1], upper[d-1], binCount, 0);
00138 MakeHistogram1d(&hist, comp);
00139 hist.Normalize();
00140
00141
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
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);
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
00167 Add(comp, comp, circleMask);
00168
00169 }
00170
00171 Histogram1dTem<Real64> hist(lower[d-1], upper[d-1], binCount, 0);
00172 MakeHistogram1d(&hist, comp);
00173 hist.Normalize();
00174
00175
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
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
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
00204 Mul(comp, comp, circleMask);
00205 }
00206
00207
00208 Array2dScalarReal64* stddev = 0;
00209 Mul(stddev, comp, comp);
00210 if(useCircularMask) {
00211
00212 Mul(stddev, stddev, circleMask);
00213 }
00214 Real64 standardDeviation = sqrt(PixSum(stddev) / pixelCount);
00215 MulVal(comp, comp, 1.0 / standardDeviation);
00216
00217
00218 Histogram1dTem<Real64> hist(lower[d-1], upper[d-1], binCount, 0);
00219 MakeHistogram1d(&hist, comp);
00220 hist.Normalize();
00221
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
00229
00230
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 } else if(descriptor == "colormoments") {
00257
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
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 } else if(descriptor == "colormomentinvariants") {
00277
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
00288
00289
00290
00291 if(binCount == 15) binCount = 37;
00292
00293
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
00319 ProjectRange(R, src, 1);
00320 ProjectRange(G, src, 2);
00321 ProjectRange(B, src, 3);
00322
00323
00324 Array2dScalarReal64* Saturation = 0;
00325
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
00337 Add(Y, G, B);
00338 Mul(Y, R, Y);
00339 MulVal(Y, Y, -1);
00340 Add(X, X, Y);
00341
00342
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);
00356 }
00357 MakeHistogram1d(&hist, H, Saturation);
00358 hist.Normalize();
00359
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
00385
00386 pixelsAround = 120;
00387 regionRect.mLeft = x - pixelsAround;
00388 regionRect.mTop = y - pixelsAround;
00389 regionRect.mRight = x + pixelsAround;
00390 regionRect.mBottom = y + pixelsAround;
00391
00392
00393
00394
00395
00396
00397
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
00412 Real64 scaleMultiplier = 10;
00413 Real64 extraBorder = 120;
00414
00415 Array2dVec3UInt8* input =
00416 ArrayCreate<Array2dVec3UInt8>(inputNoBorder->CW(), inputNoBorder->CH(), extraBorder, extraBorder);
00417 MakeFromData2<Array2dVec3UInt8,Array2dVec3UInt8>(input, inputNoBorder);
00418
00419 Pattern::FuncBorderMirror2d(input, extraBorder, extraBorder);
00420
00421
00422 CmdOptions& options = CmdOptions::GetInstance();
00423 if(options.GetInt("descriptorPreSmoothing") != 0) {
00424
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
00443 for(InterestPointList::iterator iter = pointList.begin(); iter != pointList.end(); iter++)
00444 {
00445
00446 InterestPoint* point = *iter;
00447
00448 if(point->geometryType() == "CircleZ") {
00449
00450 InterestCircle* circle(dynamic_cast<InterestCircle*>(point));
00451
00452
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
00461
00462
00463
00464
00465 ComputeRegionDescriptor(circle->mDescriptor, patch, descriptor, true, x, y);
00466
00467 delete patch;
00468 } else if(point->geometryType() == "RectangleZ") {
00469
00470 InterestRectangleZ* rectangle(dynamic_cast<InterestRectangleZ*>(point));
00471
00472
00473 Array2dVec3UInt8* patch = MakeRoi(input, rectangle->GetRect());
00474
00475
00476
00477
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
00486 }
00487 delete input;
00488 }
00489
00490 }
00491 }
00492 }
00493
00494 #endif