00001 #ifndef Impala_Core_Feature_InterestPointFeature_h
00002 #define Impala_Core_Feature_InterestPointFeature_h
00003
00004 #include "Core/Array/MakeRoi.h"
00005 #include "Core/Geometry/Rectangle.h"
00006 #include "Core/Feature/FeatureDefinition.h"
00007 #include "Core/Feature/FeatureTable.h"
00008 #include "Core/Feature/Surf.h"
00009 #include "Core/Feature/RandomForest.h"
00010 #include "Basis/Timer.h"
00011
00012 #include "Core/Matrix/MatNorm2Dist.h"
00013 #include "Core/Matrix/VectorQuantize.h"
00014 #include "Util/RandomGenerator.h"
00015
00016 #include "Core/Geometry/InterestPointList.h"
00017 #include "Core/Geometry/InterestCircle.h"
00018 #include "Core/Geometry/InterestRectangleZ.h"
00019 #include "Core/Feature/RegionDescriptor.h"
00020 #include "Core/Feature/KoenFIST2.h"
00021 #include "Core/Feature/HarrisLaplaceDetector.h"
00022 #include "Core/Feature/LaplacianDetector.h"
00023 #include "Core/Geometry/InterestPointSelector.h"
00024 #include "Core/Geometry/MaskedInterestPointSelector.h"
00025
00026 #include "Core/Feature/PointDescriptorTable.h"
00027
00028 #include <iostream>
00029 #include <fstream>
00030 #include <algorithm>
00031
00032 namespace Impala
00033 {
00034 namespace Core
00035 {
00036 namespace Feature
00037 {
00038
00039
00040 class InterestPointFeature
00041 {
00042 public:
00043 typedef Array::Array2dScalarReal64 Array2dScalarReal64;
00044 typedef Matrix::Mat Mat;
00045 typedef Geometry::InterestPointSelector InterestPointSelector;
00046 typedef Geometry::InterestPointList InterestPointList;
00047 typedef Geometry::InterestPoint InterestPoint;
00048
00049
00050 int mVerbose;
00051 int mStripBorder;
00052 bool mUseRecGauss;
00053 String mName;
00054 FeatureDefinition mFeatureDefinition;
00055 int mKeepLimited;
00056 String mOutputFormat;
00057 FeatureTable* mCodebook;
00058 Mat* mDescriptorReduce;
00059 String mDescriptorReduceFilename;
00060 bool mClusterInput;
00061 FeatureTable* mClusterInputData;
00062 String mClusterInputImage;
00063 std::vector<Vector::VectorTem<Real64>*> mLastCodebookVectors;
00064 std::vector<InterestPointSelector*> mPointSelector;
00065 bool mDynamicPointSelector;
00066 String mDynamicPointSelectorConfig;
00067 Impala::Util::Database* mDatabase;
00068 std::vector<Real64> mDenseSamplingScales;
00069 int mSurfParams[3];
00070
00071 InterestPointFeature(CmdOptions& options) :
00072 mVerbose(0),
00073 mStripBorder(0),
00074 mUseRecGauss(false),
00075 mKeepLimited(0),
00076 mCodebook(0),
00077 mDescriptorReduce(0),
00078 mClusterInput(false),
00079 mClusterInputData(0),
00080 mDynamicPointSelector(false),
00081 mDatabase(0)
00082 {
00083 mVerbose = options.GetInt("verb");
00084 mUseRecGauss = options.GetBool("recGauss");
00085 mStripBorder = options.GetInt("borderWidth");
00086 mOutputFormat = options.GetString("outputFormat");
00087
00088 mClusterInput = options.GetBool("clusterInput");
00089 mKeepLimited = options.GetInt("keepLimited");
00090 if (!options.GetBool("noRandomizeSeed"))
00091 Util::RandomGenerator::GetInstance().RandomizeSeed();
00092
00093 String detector = options.GetString("detector");
00094 mName = detector + "-" + options.GetString("descriptor");
00095 mFeatureDefinition = FeatureDefinition(mName);
00096
00097 String descriptor = options.GetString("descriptor");
00098 if((descriptor.size() >= 4) &&
00099 (descriptor.substr(descriptor.size()-4,4) == "surf"))
00100 {
00101 Core::Feature::GetDSurfOptions(options, mSurfParams[0],
00102 mSurfParams[1], mSurfParams[2]);
00103 mFeatureDefinition.AddParameter
00104 ("sc", MakeString(mSurfParams[0]) + "-" +
00105 MakeString(mSurfParams[1]) + "-" + MakeString(mSurfParams[2]));
00106 }
00107 if((detector == "harrislaplace") || (detector == "harrislaplace2"))
00108 {
00109 if(options.GetString("harrisThreshold") != "1e-9")
00110 {
00111 mFeatureDefinition.AddParameter
00112 ("ht", options.GetString("harrisThreshold"));
00113 }
00114 }
00115 if((detector == "densesampling") || (detector == "denseall"))
00116 {
00117
00118 int spacing = options.GetInt("ds_spacing");
00119 String scales = options.GetString("ds_scales");
00120
00121 Util::StringParser sp(scales);
00122 while(!sp.TheEnd())
00123 {
00124 Real64 scale = sp.GetDouble('+', false, true);
00125 mDenseSamplingScales.push_back(scale);
00126 }
00127 if(mDenseSamplingScales.size() == 0)
00128 {
00129
00130 Real64 scale = Real64(spacing) / 5;
00131
00132
00133
00134 mDenseSamplingScales.push_back(scale);
00135 }
00136 String name = MakeString(spacing);
00137 for(int i = 0; i < mDenseSamplingScales.size(); i++)
00138 {
00139 name += "-" + MakeString(mDenseSamplingScales[i]);
00140 }
00141 mFeatureDefinition.AddParameter("ds", name);
00142 }
00143
00144 mDescriptorReduceFilename = options.GetString("descriptorReduce");
00145 if(!mDescriptorReduceFilename.empty()) mFeatureDefinition.AddParameter("red", "1");
00146
00147 if(!options.GetString("descriptorOpponentWeight").empty())
00148 {
00149 mFeatureDefinition.AddParameter
00150 ("ow", options.GetString("descriptorOpponentWeight"));
00151 }
00152 if(StringStartsWith(options.GetString("pointSelector"), "dynamic-"))
00153 {
00154
00155 mDynamicPointSelector = true;
00156 String config = options.GetString("pointSelector");
00157 mFeatureDefinition.AddParameter("ps", config);
00158 config = StringReplace(config, "dynamic-", "");
00159 mDynamicPointSelectorConfig = config;
00160 }
00161 else if(options.GetString("pointSelector").size() != 0)
00162 {
00163
00164 String config = options.GetString("pointSelector");
00165 String configName = config;
00166 if(config == "pyramid-1x1-2x2")
00167 {
00168 config = "P1x1#0+P2x2#0+P2x2#1+P2x2#2+P2x2#3";
00169 }
00170 if(config == "pyramid-1x1-2x2-3x1")
00171 {
00172 config = "P1x1#0+P2x2#0+P2x2#1+P2x2#2+P2x2#3+P3x1#0+P3x1#1+P3x1#2";
00173 }
00174 if(config == "pyramid-1x1-2x2-1x3")
00175 {
00176
00177 config = "P1x1#0+P2x2#0+P2x2#1+P2x2#2+P2x2#3+P1x3#0+P1x3#1+P1x3#2";
00178 }
00179 Util::StringParser sp(config);
00180 while(!sp.TheEnd())
00181 {
00182 String selectorConfig = sp.GetString('+', false);
00183 if(selectorConfig.size() == 0) break;
00184 InterestPointSelector* selector =
00185 new InterestPointSelector(selectorConfig, mStripBorder);
00186 mPointSelector.push_back(selector);
00187 }
00188 configName = StringReplaceAll(configName, "+", "");
00189 configName = StringReplaceAll(configName, "#", "x");
00190 mFeatureDefinition.AddParameter("ps", configName);
00191 }
00192 else
00193 {
00194
00195 InterestPointSelector* selector =
00196 new InterestPointSelector("P1x1#0", mStripBorder);
00197 mPointSelector.push_back(selector);
00198 }
00199 }
00200
00201 ~InterestPointFeature()
00202 {
00203 if(mCodebook)
00204 {
00205 delete mCodebook;
00206 mCodebook = 0;
00207 }
00208 }
00209
00210 static void AddCmdOptions()
00211 {
00212 CmdOptions& options = CmdOptions::GetInstance();
00213 options.AddOption(0, "borderWidth", "size", "0");
00214 options.AddOption(0, "recGauss", "", "0");
00215 options.AddOption(0, "loadRegions", "filename", "");
00216 options.AddOption(0, "saveRegions", "filename", "");
00217 options.AddOption(0, "descriptor", "mode", "");
00218 options.AddOption(0, "output", "filename", "");
00219 options.AddOption(0, "outputFormat", "mode", "");
00220 options.AddOption(0, "descriptorBinCount","bins", "15");
00221 options.AddOption(0, "descriptorPreSmoothing","", "0");
00222 options.AddOption(0, "descriptorOpponentWeight","weight","");
00223
00224
00225 options.AddOption(0, "clusterInput", "", "0");
00226 options.AddOption(0, "keepLimited", "count", "-1");
00227 options.AddOption(0, "noRandomizeSeed", "", "0");
00228
00229
00230 options.AddOption(0, "descriptorReduce", "filename", "");
00231 options.AddOption(0, "codebook", "filename", "");
00232 options.AddOption(0, "codebookMode", "name", "hard");
00233 options.AddOption(0, "codebookSigma", "sigma", "");
00234
00235
00236 options.AddOption(0, "pointSelector", "config", "");
00237
00238
00239 options.AddOption(0, "detector", "mode", "harrislaplace");
00240
00241
00242 options.AddOption(0, "harrisThreshold", "threshold", "1e-9");
00243 options.AddOption(0, "harrisK", "k", "0.06");
00244 options.AddOption(0, "laplaceThreshold", "threshold", "0.03");
00245
00246
00247 options.AddOption(0, "ds_spacing", "pixels", "6");
00248 options.AddOption(0, "ds_scales", "scale1+scale2+...", "");
00249
00250 Core::Feature::AddDSurfOptions(options);
00251 }
00252
00253
00254 String
00255 GetFeatureName()
00256 {
00257 return mFeatureDefinition.AsString();
00258 }
00259
00260
00261 String
00262 GetFeatureNameShort()
00263 {
00264 return mFeatureDefinition.GetName();
00265 }
00266
00267
00268 void
00269 SetCodebook(String filename, Impala::Util::Database* db)
00270 {
00271 String codebook;
00272 Util::IOBuffer* buf = 0;
00273 if(db)
00274 {
00275
00276 codebook = db->GetFilePath(filename, false, false);
00277 ILOG_DEBUG("SetCodebook using DB; " << filename << "; serverName="
00278 << codebook);
00279
00280 if(codebook.empty())
00281 {
00282 ILOG_ERROR("Cannot open codebook: " << filename);
00283 exit(1);
00284 }
00285 buf = db->GetIOBuffer(codebook, true, false, "", 0, true);
00286 mDatabase = db;
00287 if(!mDescriptorReduceFilename.empty())
00288 {
00289 ReadRaw(mDescriptorReduce, db->GetFilePath(mDescriptorReduceFilename, false, false), db);
00290 mFeatureDefinition.AddParameter("red", MakeString(Matrix::MatNrCol(mDescriptorReduce)));
00291 }
00292 }
00293 else
00294 {
00295 ILOG_DEBUG("Command-line (colorDescriptor binary)");
00296 codebook = filename;
00297 buf = new Util::IOBufferFile(filename, true, true);
00298 if(!mDescriptorReduceFilename.empty())
00299 {
00300 Util::IOBuffer* buf2 = new Util::IOBufferFile(mDescriptorReduceFilename, true, true);
00301 ReadRaw(mDescriptorReduce, buf2);
00302 mFeatureDefinition.AddParameter("red", MakeString(Matrix::MatNrCol(mDescriptorReduce)));
00303 delete buf2;
00304 }
00305 }
00306
00307 ILOG_DEBUG("SetCodebook after IOBuffer " << buf);
00308 if (buf)
00309 {
00310 buf->Seek(0, SEEK_SET);
00311 char buf2[2049];
00312 buf2[2048] = '\0';
00313 buf->Read(buf2, 2048);
00314 buf->Seek(0, SEEK_SET);
00315 String recognizer(buf2);
00316 if(recognizer.find("nr strings") != String::npos)
00317 {
00318 ILOG_ERROR("Your codebook is in FeatureTableOld format!");
00319 }
00320 else
00321 {
00322 mCodebook = new FeatureTable(filename);
00323 Read(mCodebook, buf);
00324 ILOG_DEBUG("FeatureTable style: " << filename);
00325 }
00326 delete buf;
00327 }
00328 else
00329 {
00330 ILOG_ERROR("SetCodebook: IOBuffer is 0");
00331 return;
00332 }
00333
00334 ILOG_INFO("Reading codebook: " << codebook <<
00335 "; dimensionCount = " << mCodebook->GetFeatureVectorLength()
00336 << "; size = " << mCodebook->Size());
00337
00338 CmdOptions& options = CmdOptions::GetInstance();
00339 if(options.GetString("codebookMode") != "hard")
00340 {
00341 if(options.GetString("codebookMode") == "hardindex")
00342 {
00343 mFeatureDefinition.AddParameter
00344 ("cm", options.GetString("codebookMode") + "-" +
00345 FileNameBase(codebook));
00346 }
00347 else
00348 {
00349 mFeatureDefinition.AddParameter
00350 ("cm", options.GetString("codebookMode"));
00351 }
00352 }
00353 if(options.GetString("codebookSigma") != "")
00354 {
00355 mFeatureDefinition.AddParameter
00356 ("cs", options.GetString("codebookSigma"));
00357 }
00358 }
00359
00360 bool
00361 FindInterestPoints(CmdOptions& options, Array::Array2dVec3UInt8* input,
00362 Quid quid,
00363 String outputFilename, bool borderAlreadyRemoved=false,
00364 String loadRegionsFilename="")
00365 {
00366 ILOG_DEBUG("start FindInterestPoints");
00367 if(loadRegionsFilename == "")
00368 {
00369
00370 loadRegionsFilename = options.GetString("loadRegions");
00371 }
00372 String saveRegionsFilename = options.GetString("saveRegions");
00373 String detectorMode = options.GetString("detector");
00374 String descriptorMode = options.GetString("descriptor");
00375 Timer timer;
00376 Array::Array2dVec3UInt8* inputNoBorder = input;
00377 if(!borderAlreadyRemoved)
00378 {
00379
00380 Geometry::Rectangle rect(mStripBorder, mStripBorder,
00381 input->CW() - mStripBorder - 1,
00382 input->CH() - mStripBorder - 1, true);
00383 inputNoBorder = MakeRoi(input, rect);
00384 }
00385
00386 PointDescriptorTable* pointData = 0;
00387
00388
00389 ILOG_DEBUG("applying detector");
00390 if(!loadRegionsFilename.empty())
00391 {
00392
00393 pointData = PointDescriptorTable::ImportFromFile(detectorMode,
00394 loadRegionsFilename, mStripBorder);
00395 }
00396
00397 if(loadRegionsFilename.empty())
00398 {
00399 pointData = ApplyDetector(inputNoBorder, detectorMode);
00400 }
00401 if(descriptorMode.empty())
00402 {
00403
00404
00405 pointData->ExportToFile(outputFilename, mStripBorder,
00406 mOutputFormat);
00407 }
00408 if(!saveRegionsFilename.empty())
00409 {
00410 ILOG_INFO("Writing to: " << saveRegionsFilename);
00411 pointData->ExportToFile(saveRegionsFilename, mStripBorder,
00412 mOutputFormat);
00413 }
00414
00415 ILOG_DEBUG("[Timing] Region loading / applying detector finished in "
00416 << timer.SplitTimeStr());
00417
00418
00419 ILOG_DEBUG("computing descriptor");
00420 if(descriptorMode.size() != 0)
00421 {
00422 ComputeDescriptors(pointData, inputNoBorder, descriptorMode);
00423
00424 ILOG_DEBUG("[Timing] Descriptors finished at " << timer.SplitTimeStr());
00425 if(mCodebook)
00426 {
00427 ILOG_DEBUG("preparing for codebook");
00428
00429 for(int i = 0; i < mLastCodebookVectors.size(); i++)
00430 {
00431 delete mLastCodebookVectors[i];
00432 }
00433 mLastCodebookVectors.clear();
00434
00435 Timer timerProjection;
00436 pointData = ProjectOntoCodebook(pointData,
00437 options.GetString("codebookMode"),
00438 inputNoBorder->CW(), inputNoBorder->CH(),
00439 quid);
00440 ILOG_DEBUG("Just codebook projection took: " <<
00441 timerProjection.SplitTimeStr());
00442 if(outputFilename.size() != 0)
00443 {
00444 pointData->ExportToFile(outputFilename, mStripBorder,
00445 mOutputFormat);
00446 }
00447 }
00448 else
00449 {
00450
00451 if((mKeepLimited > 0) && (pointData->Size() > mKeepLimited))
00452 {
00453 ILOG_DEBUG("reducing point count");
00454
00455 pointData = ReducePointCount(pointData, mKeepLimited);
00456 }
00457
00458 if(mClusterInput)
00459 {
00460 ILOG_DEBUG("doing cluster input");
00461 InterestPointList outputPointList;
00462 pointData->ToPointList(outputPointList);
00463
00464 for(InterestPointList::iterator iter = outputPointList.begin();
00465 iter != outputPointList.end(); iter++)
00466 {
00467 InterestPoint* point = *iter;
00468 int n = point->mDescriptor.size();
00469 Vector::VectorTem<Real64> descriptor(n);
00470 for(int i = 0; i < n; i++)
00471 {
00472 descriptor.Elem(i) = point->mDescriptor[i];
00473 }
00474
00475 if(!mClusterInputData)
00476 {
00477 ILOG_DEBUG("initializing mClusterInputData");
00478
00479 FeatureDefinition def = GetFeatureName();
00480 def.AddParameter("clusterinput", "2");
00481 mClusterInputData = new FeatureTable(def, 500, n);
00482 }
00483
00484
00485
00486
00487
00488
00489 mClusterInputData->Add(mClusterInputData->Size() + 1,
00490 descriptor);
00491 }
00492 ILOG_DEBUG("done with cluster input");
00493 outputPointList.EraseAndDelete();
00494 }
00495 else
00496 {
00497 ILOG_DEBUG("writing point list");
00498 if(outputFilename.empty())
00499 {
00500 ILOG_WARN("Warning: no output file to write to. Did you forget to specify --output?");
00501 }
00502 else
00503 {
00504 pointData->ExportToFile(outputFilename, mStripBorder,
00505 mOutputFormat);
00506 }
00507 }
00508 }
00509 if(!borderAlreadyRemoved)
00510 {
00511 delete inputNoBorder;
00512 }
00513 }
00514
00515 ILOG_DEBUG("Completed " << GetFeatureName() << " in " <<
00516 timer.SplitTimeStr());
00517 delete pointData;
00518
00519 return true;
00520 }
00521 private:
00522 void
00523 AddToPyramids(int codeword, double x, double y,
00524 int imageWidth, int imageHeight, std::vector<int>& regionCounts)
00525 {
00526 for(int ps = 0; ps < mPointSelector.size(); ps++)
00527 {
00528 InterestPointSelector* selector = mPointSelector[ps];
00529 if(selector->Accept(x, y, imageWidth, imageHeight))
00530 {
00531 mLastCodebookVectors[ps]->Elem(codeword) =
00532 mLastCodebookVectors[ps]->Elem(codeword) + 1;
00533 regionCounts[ps] = regionCounts[ps] + 1;
00534 }
00535 }
00536 }
00537
00538 void
00539 ProjectUNC(Mat* matrixDescriptors, int imageWidth,
00540 int imageHeight, std::vector<int>& X, std::vector<int>& Y,
00541 std::vector<int>& regionCounts)
00542 {
00543 using namespace Matrix;
00544 Timer timerProjection;
00545 if(mDescriptorReduce)
00546 {
00547 matrixDescriptors = MatMul(matrixDescriptors, mDescriptorReduce);
00548 }
00549 Mat* matrixCodebook = mCodebook->GetColumn2()->GetStorage();
00550 ILOG_DEBUG(MatNrRow(matrixDescriptors) << " " <<
00551 MatNrCol(matrixDescriptors));
00552 ILOG_DEBUG(MatNrRow(matrixCodebook) << " " <<
00553 MatNrCol(matrixCodebook));
00554 ILOG_DEBUG("Codebook projection (init) took: " <<
00555 timerProjection.SplitTimeStr());
00556
00557 int step = 10000;
00558 for(int k = 0; k < MatNrRow(matrixDescriptors); k += step)
00559 {
00560 int s = MatNrRow(matrixDescriptors) - k;
00561 if(step < s) s = step;
00562
00563 Mat* partial = MatCreate<Mat>(s, MatNrCol(matrixDescriptors),
00564 MatE(matrixDescriptors, k, 0), true);
00565
00566
00567 Mat* distances = MatNorm2DistTransposed(partial,
00568 matrixCodebook);
00569 delete partial;
00570
00571 ILOG_DEBUG("Codebook projection (matrix) took: " <<
00572 timerProjection.SplitTimeStr());
00573 CmdOptions& options = CmdOptions::GetInstance();
00574 Real64 sigma = options.GetDouble("codebookSigma");
00575
00576
00577 for(int vj = 0; vj < s; vj++)
00578 {
00579 for(int i = 0; i < mCodebook->Size(); i++)
00580 {
00581 Real64 value = *MatE(distances, vj, i);
00582 *MatE(distances, vj, i) = exp((-0.5 * value * value) /
00583 (sigma * sigma));
00584 }
00585 }
00586
00587
00588
00589 Mat* normalizationFactor = MatSumAxis1(distances);
00590 ILOG_DEBUG("normalizationFactor: " << MatNrRow(normalizationFactor)
00591 << " " << MatNrCol(normalizationFactor));
00592
00593
00594 for(int vj = 0; vj < s; vj++)
00595 {
00596 for(int i = 0; i < mCodebook->Size(); i++)
00597 {
00598 *MatE(distances, vj, i) = *MatE(distances, vj, i) /
00599 *MatE(normalizationFactor, vj, 0);
00600 }
00601 }
00602 delete normalizationFactor;
00603
00604
00605 for(int vj = 0; vj < s; vj++)
00606 {
00607 for(int ps = 0; ps < mPointSelector.size(); ps++)
00608 {
00609 if(mPointSelector[ps]->Accept(X[k+vj], Y[k+vj],
00610 imageWidth, imageHeight))
00611 {
00612 for(int i = 0; i < mCodebook->Size(); i++)
00613 {
00614 mLastCodebookVectors[ps]->Elem(i) =
00615 mLastCodebookVectors[ps]->Elem(i) +
00616 *MatE(distances, vj, i);
00617 }
00618 regionCounts[ps] = regionCounts[ps] + 1;
00619 }
00620 }
00621 }
00622 delete distances;
00623 ILOG_DEBUG("Codebook projection (piece) took: " <<
00624 timerProjection.SplitTimeStr() << " " << mPointSelector.size());
00625 }
00626 ILOG_INFO("Codebook projection (UNC/" << MatNrRow(matrixDescriptors) <<
00627 ") took: " << timerProjection.SplitTimeStr());
00628 if(mDescriptorReduce)
00629 {
00630 delete matrixDescriptors;
00631 }
00632 }
00633
00634 void
00635 ProjectHardMatrix(Mat* matrixDescriptors,
00636 int imageWidth, int imageHeight, std::vector<int>& X,
00637 std::vector<int>& Y, std::vector<int>& regionCounts)
00638 {
00639 using namespace Matrix;
00640 Timer timerProjection;
00641 if(mDescriptorReduce)
00642 {
00643 matrixDescriptors = MatMul(matrixDescriptors, mDescriptorReduce);
00644 }
00645 Mat* matrixCodebook = mCodebook->GetColumn2()->GetStorage();
00646 ILOG_DEBUG(MatNrRow(matrixDescriptors) << " " <<
00647 MatNrCol(matrixDescriptors));
00648 ILOG_DEBUG(MatNrRow(matrixCodebook) << " " <<
00649 MatNrCol(matrixCodebook));
00650 ILOG_DEBUG("Codebook projection (init) took: " <<
00651 timerProjection.SplitTimeStr());
00652
00653 Mat* assignment =
00654 Core::Matrix::VectorQuantize(matrixDescriptors, matrixCodebook);
00655
00656 ILOG_DEBUG("Codebook projection (matrix) took: " <<
00657 timerProjection.SplitTimeStr());
00658 for(int vj = 0; vj < MatNrRow(matrixDescriptors); vj++)
00659 {
00660 Real64 bestDistance = *MatE(assignment, vj, 1);
00661 int bestIndex = static_cast<int>(*MatE(assignment, vj, 0));
00662 AddToPyramids(bestIndex, X[vj], Y[vj], imageWidth, imageHeight,
00663 regionCounts);
00664
00665
00666 }
00667 ILOG_DEBUG("Codebook projection (matrix-form) took: " <<
00668 timerProjection.SplitTimeStr());
00669 delete assignment;
00670 if(mDescriptorReduce)
00671 {
00672 delete matrixDescriptors;
00673 }
00674 }
00675
00676
00677 void
00678 ProjectHardIndex(Mat* matrixDescriptors,
00679 PointDescriptorTable* pointData)
00680 {
00681 using namespace Matrix;
00682 Timer timerProjection;
00683 if(mDescriptorReduce)
00684 {
00685 matrixDescriptors = MatMul(matrixDescriptors, mDescriptorReduce);
00686 }
00687 Mat* matrixCodebook = mCodebook->GetColumn2()->GetStorage();
00688 ILOG_DEBUG("Codebook projection (init) took: " <<
00689 timerProjection.SplitTimeStr());
00690
00691 Mat* assignment =
00692 Core::Matrix::VectorQuantize(matrixDescriptors, matrixCodebook);
00693 ILOG_INFO("Codebook projection (matrix) took: " <<
00694 timerProjection.SplitTimeStr());
00695
00696 Array::Array2dScalarReal64* newDesc = new Array::Array2dScalarReal64(1,
00697 pointData->Size(), 0, 0);
00698 for(int vj = 0; vj < MatNrRow(matrixDescriptors); vj++)
00699 {
00700 Real64 bestDistance = *MatE(assignment, vj, 1);
00701 int bestIndex = static_cast<int>(*MatE(assignment, vj, 0));
00702 *MatE(newDesc, vj, 0) = bestIndex;
00703 }
00704
00705 pointData->ReplaceAllDescriptors(newDesc);
00706 delete assignment;
00707 for(int i = 0; i < mLastCodebookVectors.size(); i++)
00708 delete mLastCodebookVectors[i];
00709 mLastCodebookVectors.clear();
00710 if(mDescriptorReduce)
00711 {
00712 delete matrixDescriptors;
00713 }
00714 }
00715
00716
00717 void
00718 ProjectForest(Mat* descriptors, int imageWidth,
00719 int imageHeight, std::vector<int>& X, std::vector<int>& Y,
00720 std::vector<int>& regionCounts)
00721 {
00722 using namespace Matrix;
00723
00724 ILOG_DEBUG("creating random forest from feature table");
00725 RandomForest forest = ReadRandomForest(mCodebook);
00726 ILOG_DEBUG("codewords: "<<GetCodebookLength(mCodebook)<<", feattable size: "<<
00727 mLastCodebookVectors[0]->Size() <<", desc count"<<
00728 MatNrRow(descriptors) <<", desc length: "<< MatNrCol(descriptors));
00729 Timer timerProjection;
00730 for(int vj = 0; vj < MatNrRow(descriptors); vj++)
00731 {
00732 for(int i=0; i<forest.size(); ++i)
00733 {
00734 RandomTree* tree = forest[i];
00735 ILOG_DEBUG("getting codeword");
00736 int codeword = tree->GetCodeWord(Vector::VectorTem<Real64>(MatNrCol(descriptors), descriptors->CPB(0, vj), true));
00737 ILOG_DEBUG("got codeword");
00738 AddToPyramids(codeword, X[vj], Y[vj], imageWidth, imageHeight,
00739 regionCounts);
00740 }
00741 }
00742 DeleteForest(forest);
00743 ILOG_DEBUG("Codebook projection (forest) took: " <<
00744 timerProjection.SplitTimeStr());
00745 }
00746
00747 PointDescriptorTable*
00748 ProjectOntoCodebook(PointDescriptorTable* pointData, String codebookMode,
00749 int imageWidth, int imageHeight, Quid q)
00750 {
00759 using namespace Matrix;
00760 ILOG_DEBUG("ProjectOntoCodebook called");
00761 PointDescriptorTable* output = new PointDescriptorTable(
00762 pointData->GetFeatureDefinition());
00763 Array::Array2dScalarInt32* tempDynamic = 0;
00764 if(mDynamicPointSelector)
00765 {
00766
00767 String filename = "PointSelector/" + mDynamicPointSelectorConfig +
00768 "/" + MakeString(q) + ".raw";
00769 Util::IOBuffer* buf = 0;
00770 if(mDatabase)
00771 {
00772
00773 filename = mDatabase->GetFilePath(filename, false, false);
00774
00775 if(filename.empty())
00776 {
00777 ILOG_ERROR("Cannot open dynamic point selector: " << filename);
00778 }
00779 buf = mDatabase->GetIOBuffer(filename, true, false, "", 0, true);
00780 }
00781 else
00782 {
00783 buf = new Util::IOBufferFile(filename, true, true);
00784 }
00785
00786
00787 ReadRaw(tempDynamic, buf);
00788 delete buf;
00789 for(int i = 0; i < tempDynamic->CH(); i++)
00790 {
00791 *tempDynamic->CPB(0, i) -= (mStripBorder + 1);
00792 *tempDynamic->CPB(1, i) -= (mStripBorder + 1);
00793 }
00794
00795 for(int ps = 0; ps < tempDynamic->CW() - 2; ps++)
00796 {
00797 mPointSelector.push_back
00798 (new Geometry::MaskedInterestPointSelector(tempDynamic, ps));
00799 }
00800 }
00801
00802 std::vector<int> regionCounts;
00803 int codebookLength = mCodebook->Size();
00804 if(codebookMode == "forest")
00805 {
00806 codebookLength = GetCodebookLength(mCodebook);
00807 ILOG_DEBUG("forest codebook length = "<< codebookLength);
00808 }
00809 for(int ps = 0; ps < mPointSelector.size(); ps++)
00810 {
00811 Vector::VectorTem<Real64>* codebookVector = new Vector::VectorTem<Real64>(codebookLength);
00812 for(int i = 0; i < codebookLength; i++)
00813 {
00814 codebookVector->Elem(i) = 0.0;
00815 }
00816 mLastCodebookVectors.push_back(codebookVector);
00817 regionCounts.push_back(0);
00818 }
00819 ILOG_DEBUG("done making codebook vector");
00820 if(pointData->Size() == 0)
00821 {
00822 delete pointData;
00823 return output;
00824 }
00825 int descriptorLength = pointData->GetDescriptorLength();
00826 std::vector<int> X;
00827 std::vector<int> Y;
00828 X.reserve(pointData->Size());
00829 Y.reserve(pointData->Size());
00830
00831 ILOG_DEBUG("extracting descriptor data");
00832 for(int it = 0; it < pointData->Size(); it++)
00833 {
00834 X.push_back(static_cast<int>(pointData->GetX(it)));
00835 Y.push_back(static_cast<int>(pointData->GetY(it)));
00836 }
00837
00838
00839 if((codebookMode != "forest") &&
00840 (mCodebook->Get2(0).Size() != descriptorLength))
00841 {
00842 if(mDescriptorReduce)
00843 {
00844 if((mCodebook->Get2(0).Size() != MatNrCol(mDescriptorReduce))
00845 || (descriptorLength != MatNrRow(mDescriptorReduce)))
00846 {
00847 ILOG_ERROR("Reduced descriptor dimensionality mismatch");
00848 throw "bye";
00849 }
00850 }
00851 else
00852 {
00853 ILOG_ERROR("ProjectOntoCodebook found visual word"<<
00854 " and descriptor of different sizes!\n\t\t"<<
00855 "codebook: "<< mCodebook->Get2(0).Size() <<
00856 ", descriptor:"<< descriptorLength);
00857 throw "Dimensionality mismatch!";
00858 }
00859 }
00860
00861
00862 Array2dScalarReal64* descriptors =
00863 new Array2dScalarReal64(descriptorLength, pointData->Size(), 0, 0,
00864 pointData->GetColumn6()->GetStorage()->mData, true);
00865
00866 ILOG_DEBUG("extracted descriptor data");
00867
00868
00869 if(codebookMode == "unc")
00870 ProjectUNC(descriptors, imageWidth, imageHeight,
00871 X, Y, regionCounts);
00872
00873 if((codebookMode == "hardmatrix") || (codebookMode == "hard"))
00874 ProjectHardMatrix(descriptors, imageWidth, imageHeight,
00875 X, Y, regionCounts);
00876
00877 if(codebookMode == "hardindex")
00878 {
00879 ProjectHardIndex(descriptors, pointData);
00880 delete descriptors;
00881 delete output;
00882 return pointData;
00883 }
00884 if(codebookMode == "forest")
00885 ProjectForest(descriptors, imageWidth, imageHeight,
00886 X, Y, regionCounts);
00887 delete descriptors;
00888
00889
00890 for(int ps = 0; ps < mPointSelector.size(); ps++)
00891 {
00892
00893 int regionCount = regionCounts[ps];
00894 ILOG_DEBUG("regCount " << regionCount);
00895 if(regionCount == 0)
00896 regionCount = 1;
00897 for(int i = 0; i < codebookLength; i++)
00898 {
00899 mLastCodebookVectors[ps]->Elem(i) =
00900 mLastCodebookVectors[ps]->Elem(i) / regionCount;
00901 }
00902 }
00903 if(mPointSelector.size() > 0)
00904 output->SetDescriptorLength(codebookLength);
00905 output->Reserve(mPointSelector.size(), false);
00906 for(int ps = 0; ps < mPointSelector.size(); ps++)
00907 {
00908 output->Add(0, 0, 0, 0, 0);
00909
00910
00911 output->SetDescriptor(ps, *(mLastCodebookVectors[ps]));
00912 }
00913
00914 if(mDynamicPointSelector)
00915 {
00916 for(int ps = 0; ps < mPointSelector.size(); ps++)
00917 {
00918 delete mPointSelector[ps];
00919 }
00920 mPointSelector.clear();
00921 delete tempDynamic;
00922 }
00923 delete pointData;
00924 return output;
00925 }
00926
00927
00928 PointDescriptorTable*
00929 ReducePointCount(PointDescriptorTable* pointData, int keepCount)
00930 {
00931 std::vector<int> indices;
00932 bool* keepers = new bool[pointData->Size()];
00933 for(int j = 0; j < pointData->Size(); j++)
00934 {
00935 indices.push_back(j);
00936 keepers[j] = false;
00937 }
00938
00939
00940 Util::RandomGenerator::GetInstance().PermutateVector(indices);
00941
00942 for(int j = 0; j < keepCount; j++)
00943 {
00944 keepers[indices[j]] = true;
00945 }
00946
00947 PointDescriptorTable* output = new PointDescriptorTable(pointData->GetFeatureDefinition());
00948 output->SetDescriptorLength(pointData->GetDescriptorLength());
00949 Select(output, pointData, keepers, false);
00950 delete pointData;
00951 return output;
00952 }
00953
00954
00955 template<class SrcArrayT>
00956 PointDescriptorTable*
00957 DenseAllDetector(SrcArrayT* input)
00958 {
00959 PointDescriptorTable* output = new PointDescriptorTable();
00960 int w = input->CW();
00961 int h = input->CH();
00962 output->SetEmpty();
00963 output->Reserve(w * h * mDenseSamplingScales.size(), false);
00964 for(int y = 0; y < h; y += 1)
00965 {
00966 for(int x = 0; x < w; x++)
00967 {
00968 for(int q = 0; q < mDenseSamplingScales.size(); q++)
00969 {
00970 output->Add(x, y, mDenseSamplingScales[q], 0, 0);
00971 }
00972 }
00973 }
00974 ILOG_INFO("Points detected: " << output->Size());
00975 return output;
00976 }
00977
00978
00979 template<class SrcArrayT>
00980 PointDescriptorTable*
00981 DenseSamplingDetector(SrcArrayT* input, int spacing)
00982 {
00983 PointDescriptorTable* output = new PointDescriptorTable();
00984 int halfspacing = spacing / 2;
00985 int w = input->CW();
00986 int h = input->CH();
00987 int i = 0;
00988 for(int y = spacing; y < h - spacing; y += spacing)
00989 {
00990 int x = spacing;
00991 if(i % 2 == 0)
00992 {
00993 x += halfspacing;
00994 }
00995 for(; x < w - spacing; x += spacing)
00996 {
00997 for(int q = 0; q < mDenseSamplingScales.size(); q++)
00998 {
00999
01000
01005
01006 output->Add(x, y, mDenseSamplingScales[q], 0, 0);
01007 }
01008 }
01009 i += 1;
01010 }
01011 return output;
01012 }
01013
01014
01015 PointDescriptorTable*
01016 ApplyDetector(Array::Array2dVec3UInt8* inputNoBorder, String detectorMode)
01017 {
01018 CmdOptions& options = CmdOptions::GetInstance();
01019 Real64 harrisThreshold = options.GetDouble("harrisThreshold");
01020 Real64 harrisK = options.GetDouble("harrisK");
01021 Real64 laplaceThreshold = options.GetDouble("laplaceThreshold");
01022
01023 PointDescriptorTable* output = 0;
01024
01025 if((detectorMode == "harrislaplace") || (detectorMode == "harrislaplace2"))
01026 {
01027 HarrisLaplaceDetector detector(mUseRecGauss);
01028 detector.mBackwardsCompatible = false;
01029 output = detector.HLDetector(inputNoBorder, harrisThreshold,
01030 harrisK, laplaceThreshold);
01031 }
01032 else if(detectorMode == "colorharrislaplace")
01033 {
01034
01035
01036 HarrisLaplaceDetector detector(mUseRecGauss);
01037 detector.mBackwardsCompatible = false;
01038 output = detector.CHLDetector(inputNoBorder, harrisThreshold,
01039 harrisK, laplaceThreshold);
01040 }
01041 else if(detectorMode == "laplacian")
01042 {
01043 output = LaplacianDetector(inputNoBorder, true);
01044 }
01045 else if(detectorMode == "densesampling")
01046 {
01047 int spacing = options.GetInt("ds_spacing");
01048 output = DenseSamplingDetector(inputNoBorder, spacing);
01049 }
01050 else if(detectorMode == "denseall")
01051 {
01052 output = DenseAllDetector(inputNoBorder);
01053 }
01054 else if(detectorMode == "none")
01055 {
01056
01057
01058 output = new PointDescriptorTable();
01059 }
01060 else
01061 {
01062 ILOG_ERROR("[ERROR] Unknown detector mode: " << detectorMode);
01063 return 0;
01064 }
01065 output->SetFeatureDefinition(FeatureDefinition(detectorMode));
01066 return output;
01067 }
01068
01069
01070 void
01071 ComputeDescriptors(PointDescriptorTable* pointData,
01072 Array::Array2dVec3UInt8* inputNoBorder,
01073 String descriptorMode)
01074 {
01075 if((descriptorMode == "huesift") || (descriptorMode == "huefist"))
01076 {
01077 CalculateFISTDescriptors(inputNoBorder, pointData, "sift");
01078 InterestPointList outputPointList;
01079 pointData->ToPointList(outputPointList);
01080 CalculateRegionDescriptors(inputNoBorder, outputPointList,
01081 "huehistogram");
01082
01083
01084 for(InterestPointList::iterator iter = outputPointList.begin();
01085 iter != outputPointList.end(); iter++)
01086 {
01087 InterestPoint* point = *iter;
01088 for(int i = 128; i < point->mDescriptor.size(); i++)
01089 {
01090 point->mDescriptor[i] =
01091 static_cast<int>(point->mDescriptor[i] * 512);
01092 }
01093 }
01094 pointData->SetEmpty();
01095 pointData->FromPointList(outputPointList);
01096 outputPointList.EraseAndDelete();
01097 }
01098 else if((descriptorMode.size() >= 4) &&
01099 (descriptorMode.substr(descriptorMode.size()-4,4) == "fist"))
01100 {
01101 CalculateFISTDescriptors
01102 (inputNoBorder, pointData, descriptorMode);
01103 }
01104 else if((descriptorMode.size() >= 4) &&
01105 (descriptorMode.substr(descriptorMode.size()-4,4) == "sift"))
01106 {
01107 CalculateFISTDescriptors
01108 (inputNoBorder, pointData, descriptorMode);
01109 }
01110 else if((descriptorMode.size() >= 4) &&
01111 (descriptorMode.substr(descriptorMode.size()-4,4) == "surf"))
01112 {
01113 InterestPointList outputPointList;
01114 pointData->ToPointList(outputPointList);
01115 CalculateSurfDescriptors
01116 (inputNoBorder, outputPointList, descriptorMode, mSurfParams[0],
01117 mSurfParams[1], mSurfParams[2]);
01118 pointData->SetEmpty();
01119 pointData->FromPointList(outputPointList);
01120 outputPointList.EraseAndDelete();
01121 }
01122 else
01123 {
01124 InterestPointList outputPointList;
01125 pointData->ToPointList(outputPointList);
01126 CalculateRegionDescriptors
01127 (inputNoBorder, outputPointList, descriptorMode);
01128 pointData->SetEmpty();
01129 pointData->FromPointList(outputPointList);
01130 outputPointList.EraseAndDelete();
01131 }
01132 }
01133
01134
01135 ILOG_VAR_DEC;
01136 };
01137
01138 ILOG_VAR_INIT(InterestPointFeature, Core.Feature);
01139
01140 }
01141 }
01142 }
01143
01144 #endif