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