Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

InterestPointFeature.h

Go to the documentation of this file.
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     // command line parameters
00050     int         mVerbose;
00051     int         mStripBorder;
00052     bool        mUseRecGauss;
00053     String      mName;         // for display/filename purposes
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;//used in InterestPointProc
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             // detector config
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                 // fallback to estimate
00130                 Real64 scale = Real64(spacing) / 5;
00131                 // Most computation code uses 4*scale for the circular region size.
00132                 // Therefore, it makes sense to not provide the 'actual' region of
00133                 // interest here, but something smaller.
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             // keep mPointSelector empty: we load it on-demand
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             // filter on location (spatial pyramid)
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             {   // this is vertical (!)
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                 // this is division into three horizontal bars
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             // default: a filter spanning the complete image
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         /* clustering support (i.e. when not in codebook mode) */
00225         options.AddOption(0, "clusterInput",     "",            "0");
00226         options.AddOption(0, "keepLimited",      "count",       "-1");
00227         options.AddOption(0, "noRandomizeSeed",  "",            "0");
00228 
00229         /* codebook support */
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         /* Lazebnik spatial pyramid support */
00236         options.AddOption(0, "pointSelector",    "config",    "");
00237 
00238         /*** detectors ***/
00239         options.AddOption(0, "detector",         "mode",        "harrislaplace");
00240 
00241         /* for Harris-laplace detectors */
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         /* for the dense sampling detector */
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             /* translate this name into a complete path */
00276             codebook = db->GetFilePath(filename, false, false);
00277             ILOG_DEBUG("SetCodebook using DB; " << filename << "; serverName="
00278                        << codebook);
00279             /* read it */
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             {   // nr strings : then FeatureTableOld
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,     // identifies input image data
00363                        String outputFilename, bool borderAlreadyRemoved=false,
00364                        String loadRegionsFilename="")
00365     {
00366         ILOG_DEBUG("start FindInterestPoints");
00367         if(loadRegionsFilename == "")
00368         {
00369             // try the command-line argument if it is not already specified
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             // remove the border, if requested
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         /* Apply detector */
00389         ILOG_DEBUG("applying detector");
00390         if(!loadRegionsFilename.empty())
00391         {
00392             // load the points from file
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             // dump the interest regions to the output stream if we are not
00404             // going to compute descriptors later
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         /* descriptor computation */
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                 // clean up previous codebook vectors (if any)
00429                 for(int i = 0; i < mLastCodebookVectors.size(); i++)
00430                 {
00431                     delete mLastCodebookVectors[i];
00432                 }
00433                 mLastCodebookVectors.clear();
00434                 /* project it onto a codebook */
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                 // do reduction
00451                 if((mKeepLimited > 0) && (pointData->Size() > mKeepLimited))
00452                 {
00453                     ILOG_DEBUG("reducing point count");
00454                     // we might have to limit the number of points
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                             // initialize the table
00479                             FeatureDefinition def = GetFeatureName();
00480                             def.AddParameter("clusterinput", "2");
00481                             mClusterInputData = new FeatureTable(def, 500, n);
00482                         }
00483 
00484                         // string representation of point:
00485                         //point->Serialize(borderOffset+1, borderOffset+1)
00486                         //mClusterInputData->Add(mClusterInputImage + " " +
00487                         //point->Serialize(), descriptor); TODO: create proper
00488                         //CLUSTERINPUT quid class
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             // result will be a (#partial-descriptors, codebook size) matrix
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             // pull a Gaussian kernel over the Euclidian distances
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             // sum over axis 0 for the normalization factor
00588             // expected size is (#descriptors, 1)
00589             Mat* normalizationFactor = MatSumAxis1(distances);
00590             ILOG_DEBUG("normalizationFactor: " << MatNrRow(normalizationFactor)
00591                        << " " << MatNrCol(normalizationFactor));
00592 
00593             // perform normalization
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             // remains: sum over the *right* descriptors
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         // result will be a (#descriptors, 2) matrix
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             //std::cout << "Codebook projection (inner loop) took: " <<
00665             //timerProjection.SplitTimeStr() << std::endl;
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         // result will be a (#descriptors, 2) matrix
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         // this call also takes ownership
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         // make trees from the table
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             // set the point selector configuration based on the image
00767             String filename = "PointSelector/" + mDynamicPointSelectorConfig +
00768                               "/" + MakeString(q) + ".raw";
00769             Util::IOBuffer* buf = 0;
00770             if(mDatabase)
00771             {
00772                 /* translate this name into a complete path */
00773                 filename = mDatabase->GetFilePath(filename, false, false);
00774                 /* read it */
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             // load the selectors from file
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         // dimensionality checks
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         // create a wrapper with the correct dimensions
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         // Visual word uncertainty (UNC)
00869         if(codebookMode == "unc")
00870             ProjectUNC(descriptors, imageWidth, imageHeight, 
00871                        X, Y, regionCounts);
00872         // hard assignment, matrix style
00873         if((codebookMode == "hardmatrix") || (codebookMode == "hard"))
00874             ProjectHardMatrix(descriptors, imageWidth, imageHeight,
00875                               X, Y, regionCounts);
00876         // hard assignment, matrix style, and only output the indices (special)
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         // normalize so it sums to one
00890         for(int ps = 0; ps < mPointSelector.size(); ps++)
00891         {
00892             // debugStream << "\n\npyramid part #"<<ps<<"\n";
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             //for(int i = 0; i < codebookLength; i++)
00910             //    std::cout << mLastCodebookVectors[ps]->Elem(i) << " ";
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         // do not know how to initialize this random number generator
00939         //std::random_shuffle(indices.begin(), indices.end());
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                     //Real64 scale = sqrt(Real64(spacing * spacing + spacing *
01000                     //spacing));
01005                     //scale = scale / 4;
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             // recommendation: set harrisThreshold to at least 0.001 in color
01035             // mode (due to very different ranges!)
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             // we don't add point in the detector phase, they are added in the
01057             // descsriptor fase. see Core/Feature/Surf.h for an example
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             // now fix the range of hue...
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 } // namespace Koen
01141 } // namespace Sandbox
01142 } // namespace Impala
01143 
01144 #endif

Generated on Fri Mar 19 09:31:07 2010 for ImpalaSrc by  doxygen 1.5.1