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

HarrisLaplaceDetector.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Feature_HarrisLaplaceDetector_h
00002 #define Impala_Core_Feature_HarrisLaplaceDetector_h
00003 
00004 #include "Core/Array/Pattern/PatInOutOp.h"
00005 #include "Core/Array/Abs.h"
00006 #include "Core/Array/PixMax.h"
00007 #include "Core/Array/Dilation.h"
00008 #include "Core/Array/Resample.h"
00009 #include "Core/Array/GaussDerivative.h"
00010 #include "Core/Array/RecGauss.h"
00011 #include "Core/Array/Trait/BpoEqual.h"
00012 #include "Core/Array/Harris.h"
00013 #include "Core/Array/RGB2Gray.h"
00014 #include "Core/Array/Rgb2Ooo.h"
00015 #include "Core/Geometry/Rectangle.h"
00016 #include "Core/Array/Laplacian.h"
00017 #include "Basis/Timer.h"
00018 
00019 #include "Core/Feature/PointDescriptorTable.h"
00020 #include "Core/Table/Sort.h"
00021 
00022 #include <iostream> 
00023 #include <fstream>
00024 #include <algorithm>
00025 #include <iterator>
00026 
00027 namespace Impala
00028 {
00029 namespace Core
00030 {
00031 namespace Feature
00032 {
00033 
00034 
00035 class HarrisLaplaceDetector
00036 {
00037 public:
00038     typedef Array::Array2dScalarReal64 Array2dScalarReal64;
00039     typedef Array::Array2dVec3UInt8 Array2dVec3UInt8;
00040     typedef Array::Array2dVec3Real64 Array2dVec3Real64;
00041 
00042     // command line parameters
00043     Real64      mPrecision;
00044     Real64      mSigmaA;
00045     bool        mUseRecGauss;
00046     bool        mBackwardsCompatible;
00047     
00048     HarrisLaplaceDetector(bool useRecGauss=false) : 
00049         mPrecision(5.0),     // needs to be this high for better Matlab correspondance
00050         mSigmaA(3.0), 
00051         mUseRecGauss(useRecGauss),
00052         mBackwardsCompatible(true)
00053     { 
00054     }
00055 
00056     class MyPoint 
00057     {
00058     public:
00059         Real64 mDetectionScale;
00060         Real64 mScale;
00061         Real64 mCornerness;
00062         int mX;
00063         int mY;
00064     
00065         MyPoint(int x, int y, Real64 cornerness)
00066             : mX(x), mY(y), mCornerness(cornerness)
00067         {
00068         }
00069     };
00070     
00071     typedef std::vector<MyPoint*> MyPointList;
00072     typedef std::back_insert_iterator<MyPointList> MyPointListBI;
00073 
00074     class ExportPoints
00075     {
00076     public:
00077         typedef Array::Pattern::TagPixOpOut       DirectionCategory;
00078         typedef Array::Pattern::TagTransVar       TransVarianceCategory;
00079         typedef Array::Pattern::Tag1Phase         PhaseCategory;
00080     
00081         ExportPoints(MyPointListBI& pListBI,
00082                      Real64 harrisThreshold) :
00083             mHarrisThreshold(harrisThreshold), mPListBI(pListBI)
00084         {
00085         }
00086     
00087         void
00088         DoIt(const Real64& s, int x, int y)
00089         {
00090             if(s > mHarrisThreshold) {
00091                 *mPListBI++ = new MyPoint(x, y, s);
00092             }
00093         }
00094     
00095     private:
00096         Real64 mHarrisThreshold;
00097         MyPointListBI& mPListBI;
00098     };
00099     
00100     // finds max points and stores result in dst as well as pList
00101     void
00102     DoMaxPoints(Array2dScalarReal64* src,
00103                 MyPointListBI pListBI,
00104                 Real64 harrisThreshold)
00105     {
00106         using namespace Impala::Core::Array;
00107         int cw = 2*mSigmaA + 1;
00108         int ch = 2*mSigmaA + 1;
00109         Array2dScalarReal64* ker = ArrayCreate<Array2dScalarReal64>(cw, ch);
00110         Core::Matrix::MatSet(ker, 0);
00111     
00112         Array2dScalarReal64* tmp1 = 0;
00113         Dilation(tmp1, src, ker);
00114         Trait::BpoEqual<Array2dScalarReal64, Array2dScalarReal64,
00115                         Array2dScalarReal64> bpo(0.0000000000000001);
00116         Pattern::PatBinaryPixOp(tmp1, tmp1, src, bpo); // src == dilated implies local max
00117         Mul(tmp1, tmp1, src); // obtain orignal values for local max from src
00118         Real64 theMax = PixMax(tmp1);
00119         //std::cout << "theMax : " << theMax << std::endl;
00120     
00121         ExportPoints expPoints(pListBI, harrisThreshold); // obtain coordinates
00122         Pattern::PatInOutOp(tmp1, expPoints);
00123     
00124         delete tmp1;
00125         delete ker;
00126     }
00127     
00128     void
00129     harrisCornerDetector(MyPointList& pointList,
00130                          Array2dScalarReal64* imIntensity,
00131                          Real64 sigmaN, Real64 harrisK, Real64 harrisThreshold) 
00132     {
00133         Real64 sigmaIntegr = sigmaN;
00134         Real64 sigmaDiff = 0.7125 * sigmaN;
00135     
00136         // compute Lx and Ly Gaussian derivatives
00137         Array2dScalarReal64* Lx = 0;
00138         Array2dScalarReal64* Ly = 0;
00139         if(mUseRecGauss)
00140         {
00141             RecGauss(Lx, imIntensity, sigmaDiff, sigmaDiff, 1, 0, mPrecision);
00142             RecGauss(Ly, imIntensity, sigmaDiff, sigmaDiff, 0, 1, mPrecision);
00143         } else {
00144             GaussDerivative(Lx, imIntensity, sigmaDiff, 1, 0, mPrecision);
00145             GaussDerivative(Ly, imIntensity, sigmaDiff, 0, 1, mPrecision);
00146         }
00147         
00148         // VERY IMPORTANT: SCALE MULTIPLIER!
00149         Array2dScalarReal64* Lx2 = 0;    // aka mu11
00150         Mul(Lx2, Lx, Lx);
00151         MulVal(Lx2, Lx2, sigmaDiff * sigmaDiff);
00152     
00153         Array2dScalarReal64* Ly2 = 0;    // aka mu22
00154         Mul(Ly2, Ly, Ly);
00155         MulVal(Ly2, Ly2, sigmaDiff * sigmaDiff);
00156     
00157         Array2dScalarReal64* LxLy = 0;   // aka mu12/mu21
00158         Mul(LxLy, Lx, Ly);
00159         MulVal(LxLy, LxLy, sigmaDiff * sigmaDiff);
00160     
00161         delete Lx;
00162         delete Ly;
00163     
00164         // compute Harris  
00165         Array2dScalarReal64* harrisOutput = 0;
00166         Array::Harris<Array2dScalarReal64>(harrisOutput, Lx2, Ly2, LxLy,
00167                                            sigmaIntegr, harrisK, mUseRecGauss);
00168     
00169         delete Lx2;
00170         delete Ly2;
00171         delete LxLy;
00172     
00173         DoMaxPoints(harrisOutput, std::back_inserter(pointList), harrisThreshold);
00174         
00175         // write the Harris cornerness to an image on disk
00176         /*std::string output = "debug.png";
00177         Array2dVec3UInt8* buf = ArrayCreate<Array2dVec3UInt8>
00178             (harrisOutput->CW(), harrisOutput->CH());
00179         GetRgbPixels(harrisOutput, buf->CPB(), std::string("Stretch"));
00180     
00181         WritePng(buf, output);
00182         delete buf;*/
00183         
00184         delete harrisOutput;
00185     }
00186 
00187     // multi-channel version
00188     template<class SrcArrayT>
00189     void
00190     harrisCornerDetector(MyPointList& pointList,
00191                          SrcArrayT* imColor, Real64 sigmaN, Real64 harrisK,
00192                          Real64 harrisThreshold) 
00193     {
00194         Real64 sigmaIntegr = sigmaN;
00195         Real64 sigmaDiff = 0.7125 * sigmaN;
00196         
00197         Array2dScalarReal64* TLx2 = 0;
00198         Array2dScalarReal64* TLy2 = 0;
00199         Array2dScalarReal64* TLxLy = 0;
00200     
00201         for (int d=1 ; d<=imColor->ElemSize() ; d++) {
00202             Array2dScalarReal64* imIntensity = 0;
00203             ProjectRange(imIntensity, imColor, d);
00204         
00205             // compute Lx and Ly Gaussian derivatives
00206             Array2dScalarReal64* Lx = 0;
00207             Array2dScalarReal64* Ly = 0;
00208             if(mUseRecGauss)
00209             {
00210                 RecGauss(Lx, imIntensity, sigmaDiff, sigmaDiff, 1, 0, mPrecision);
00211                 RecGauss(Ly, imIntensity, sigmaDiff, sigmaDiff, 0, 1, mPrecision);
00212             } else {
00213                 GaussDerivative(Lx, imIntensity, sigmaDiff, 1, 0, mPrecision);
00214                 GaussDerivative(Ly, imIntensity, sigmaDiff, 0, 1, mPrecision);
00215             }
00216             
00217             delete imIntensity;
00218             
00219             // VERY IMPORTANT: SCALE MULTIPLIER!
00220             Array2dScalarReal64* Lx2 = 0;    // aka mu11
00221             Mul(Lx2, Lx, Lx);
00222             MulVal(Lx2, Lx2, sigmaDiff * sigmaDiff);
00223         
00224             Array2dScalarReal64* Ly2 = 0;    // aka mu22
00225             Mul(Ly2, Ly, Ly);
00226             MulVal(Ly2, Ly2, sigmaDiff * sigmaDiff);
00227         
00228             Array2dScalarReal64* LxLy = 0;   // aka mu12/mu21
00229             Mul(LxLy, Lx, Ly);
00230             MulVal(LxLy, LxLy, sigmaDiff * sigmaDiff);
00231         
00232             delete Lx;
00233             delete Ly;
00234             
00235             if(d == 1) {
00236                 TLx2 = Lx2;
00237                 TLy2 = Ly2;
00238                 TLxLy = LxLy;
00239             } else {
00240                 Add(TLx2,TLx2,Lx2);
00241                 Add(TLy2,TLy2,Ly2);
00242                 Add(TLxLy,TLxLy,LxLy);
00243                 delete Lx2;
00244                 delete Ly2;
00245                 delete LxLy;
00246             }
00247         }
00248         
00249         // compute Harris  
00250         Array2dScalarReal64* harrisOutput = 0;
00251         Array::Harris<Array2dScalarReal64>(harrisOutput, TLx2, TLy2, TLxLy,
00252                                            sigmaIntegr, harrisK, mUseRecGauss);
00253         delete TLx2;
00254         delete TLy2;
00255         delete TLxLy;
00256         DoMaxPoints(harrisOutput, std::back_inserter(pointList), harrisThreshold);
00257             
00258         // write the Harris cornerness to an image on disk
00259         /*std::string output = "debug.png";
00260         Array2dVec3UInt8* buf = ArrayCreate<Array2dVec3UInt8>
00261             (harrisOutput->CW(), harrisOutput->CH());
00262         GetRgbPixels(harrisOutput, buf->CPB(), std::string("Stretch"));
00263     
00264         WritePng(buf, output);
00265         delete buf;*/
00266 
00267         delete harrisOutput;
00268     }
00269         
00270     
00271     template<class SrcArrayT>
00272     void
00273     laplacianScaleSelection(PointDescriptorTable* output, SrcArrayT* imIntensity, MyPointList& pointList, Real64 laplaceThreshold) 
00274     {
00275         std::vector<Real64> precomputeScales;
00276         std::vector<Array2dScalarReal64*> cache;
00277         for(int i = 0; i < 21; i++) {
00278             Real64 sigma = pow(sqrt(sqrt(Real64(2))),i) * 0.75;
00279             precomputeScales.push_back(sigma);
00280             Array2dScalarReal64* tmp = 0;
00281             Laplacian(tmp, imIntensity, sigma, 2, mUseRecGauss, mPrecision);
00282             Abs(tmp, tmp);
00283             cache.push_back(tmp);
00284 
00285             ILOG_DEBUG("Computing Laplacian scale: " << sigma);
00286         }
00287         
00288         typedef std::pair<int, std::pair<int, int> > MyKey;
00289         std::map<MyKey, int> alreadyHavePoint;
00290 
00291         for(MyPointList::iterator iter = pointList.begin(); iter != pointList.end(); iter++)
00292         {
00293             MyPoint* point(*iter);
00294             Real64 sigmaN = point->mDetectionScale;
00295 
00296             // we must find the index of the nearest sigma in precomputeScales
00297             int nearestIndex = 0;
00298             Real64 smallestDifference = 999;
00299             for(int i = 0; i < precomputeScales.size(); i++) {
00300                 Real64 difference;
00301                 if(mBackwardsCompatible)
00302                 {
00303                     // make the current (wrong) behavior explicit
00304                     difference = static_cast<int>(abs(precomputeScales[i] - sigmaN));
00305                 }
00306                 else
00307                 {
00308                     difference = fabs(precomputeScales[i] - sigmaN);
00309                 }
00310                 if(difference < smallestDifference) 
00311                 {
00312                     smallestDifference = difference;
00313                     nearestIndex = i;
00314                 }
00315             }
00316             if(smallestDifference > 0.0001) {
00317                 ILOG_WARN("WARNING: scale mismatch");
00318             }
00319     
00320             std::vector<int> interestingScales;
00321             std::vector<Real64> laplacianValues;
00322             //std::cout << "LAP: ";
00323             for(int i = 0; i < precomputeScales.size(); i++) {
00324                 if((i >= nearestIndex - 4) && (i <= nearestIndex + 4)) {
00325                     interestingScales.push_back(i);
00326                     // lookup the Laplacian value for this cached scale
00327                     laplacianValues.push_back(cache[i]->Value(point->mX, point->mY));
00328                     //std::cout << cache[i]->Value(point.mX, point.mY) << " ";
00329                 }
00330             }
00331             //std::cout << std::endl;
00332     
00333             /*std::cout << "plot([";
00334             for(int i = 0; i < precomputeScales.size(); i++) {
00335                 std::cout << cache[i]->Value(point.mX, point.mY) << " ";
00336             }
00337             std::cout << "])" << std::endl;*/
00338             
00339             // laplacianValues now contains the values of the Laplacian at interestingScales
00340     
00341             // select the local maximum
00342             int nrFound = 0;
00343             for(int i = 1; i < interestingScales.size() - 1; i++) {
00344                 if((laplacianValues[i] > laplacianValues[i-1]) &&
00345                    (laplacianValues[i] > laplacianValues[i+1]))
00346                 {
00347                     if(laplacianValues[i] > laplaceThreshold) {
00348                         MyKey key(std::make_pair(point->mX, std::make_pair(point->mY, interestingScales[i])));
00349                         if(alreadyHavePoint.find(key) == alreadyHavePoint.end())
00350                         {
00351                             alreadyHavePoint[key] = 0;
00352                             output->Add(point->mX, point->mY, precomputeScales[interestingScales[i]], 0, point->mCornerness);
00353                             nrFound++;
00354                         }
00355                     }
00356                 }
00357             }
00358         }
00359         for(int i = 0; i < cache.size(); i++) {
00360             delete cache[i];
00361         }
00362     }
00363 
00364     void
00365     BoostImage(Array2dVec3Real64*& output, Array2dVec3UInt8* input, Real64 w1, Real64 w2, Real64 w3)
00366     {
00367         Array2dVec3Real64* opponentImage = 0;
00368         Rgb2Ooo(opponentImage, input);
00369 
00370         Array2dScalarReal64* channel1 = 0;
00371         ProjectRange(channel1, opponentImage, 1);
00372         MulVal(channel1, channel1, w1);
00373 
00374         Array2dScalarReal64* channel2 = 0;
00375         ProjectRange(channel2, opponentImage, 2);
00376         MulVal(channel2, channel2, w2);
00377 
00378         Array2dScalarReal64* channel3 = 0;
00379         ProjectRange(channel3, opponentImage, 3);
00380         MulVal(channel3, channel3, w3);
00381         
00382         MakeFrom3Images(output, channel1, channel2, channel3);
00383         delete channel1;
00384         delete channel2;
00385         delete channel3;
00386         delete opponentImage;
00387     }
00388     
00389 
00390     PointDescriptorTable*
00391     CHLDetector(Array2dVec3UInt8* input, Real64 harrisThreshold, Real64 harrisK, Real64 laplaceThreshold)
00392     {
00393         Timer timer;
00394         PointDescriptorTable* output = new PointDescriptorTable();
00395     
00396         // boost image
00397         Array2dVec3Real64* imBoosted = 0;
00398         BoostImage(imBoosted, input, 0.065, 0.850, 0.524);
00399       
00402         //MulVal(imIntensity, imIntensity, 1 / 255.0);
00403         
00404         // Harris corner detection
00405         MyPointList centroids;
00406         Real64 sigmaZero = 0.75;
00407         Real64 borderIgnoreSize = 4.0;
00408         for(int sigmaCounter = 1; sigmaCounter <= 8; sigmaCounter++) 
00409         {
00410             Real64 sigmaN = pow(sqrt(Real64(2)), sigmaCounter) * sigmaZero;   
00411             MyPointList pointList;
00412             harrisCornerDetector(pointList, imBoosted, sigmaN, harrisK, harrisThreshold);
00413             for(MyPointList::iterator iter = pointList.begin(); iter != pointList.end(); iter++)
00414             {
00415                 MyPoint* point(*iter);
00416                 
00417                 point->mDetectionScale = sigmaN;
00418                 //ILOG_DEBUG("   " << point->mX << " " << point->mY << " " << point->mCornerness << " " << point->mDetectionScale);
00419                 if((point->mX < borderIgnoreSize) ||
00420                    (point->mY < borderIgnoreSize) ||
00421                    (point->mX >= imBoosted->CW() - borderIgnoreSize) ||
00422                    (point->mY >= imBoosted->CH() - borderIgnoreSize)) 
00423                 {
00424                     ILOG_DEBUG("   " << point->mX << " " << point->mY << " BORDER CLOSENESS REJECT");
00425                     continue;
00426                 }
00427                 centroids.push_back(point);
00428             }
00429             ILOG_DEBUG(sigmaN << " " << pointList.size());
00430         }
00431         ILOG_INFO("Harris corner detector found " << centroids.size() << " points");
00432         ILOG_DEBUG("[Timing2] HarrisCornerDetector " << timer.SplitTimeStr());
00433         
00434         // Laplacian scale selection
00435         laplacianScaleSelection(output, imBoosted, centroids, laplaceThreshold);
00436     
00437         delete imBoosted;
00438     
00439         ILOG_INFO("Laplacian scale selection left " << output->Size() << " points");
00440         ILOG_DEBUG("[Timing2] LaplacianScaleSelection" << timer.SplitTimeStr());
00441         
00442         // now sort the points by cornerness
00443         SortOnColumn5(output, false);
00444         return output;
00445     }
00446     
00447     
00448     template<class SrcArrayT>
00449     PointDescriptorTable*
00450     HLDetector(SrcArrayT* input, Real64 harrisThreshold, Real64 harrisK, Real64 laplaceThreshold)
00451     {
00452         Timer timer;
00453         PointDescriptorTable* output = new PointDescriptorTable();
00454     
00455         // convert to grey-scale
00456         Array2dScalarReal64* imIntensity = 0;
00457         RGB2Gray(imIntensity, input);
00458       
00459         // scale intensity to the range 0..1 instead of 0..255 so it is comparable to Matlab
00460         MulVal(imIntensity, imIntensity, 1 / 255.0);
00461         
00462         // Harris corner detection
00463         MyPointList centroids;
00464         Real64 sigmaZero = 0.75;
00465         Real64 borderIgnoreSize = 4.0;
00466         for(int sigmaCounter = 1; sigmaCounter <= 8; sigmaCounter++) 
00467         {
00468             Real64 sigmaN = pow(sqrt(Real64(2)), sigmaCounter) * sigmaZero;   
00469             MyPointList pointList;
00470             harrisCornerDetector(pointList, imIntensity, sigmaN, harrisK, harrisThreshold);
00471             for(MyPointList::iterator iter = pointList.begin(); iter != pointList.end(); iter++)
00472             {
00473                 MyPoint* point(*iter);
00474                 
00475                 point->mDetectionScale = sigmaN;
00476                 //ILOG_DEBUG("   " << point->mX << " " << point->mY << " " << point->mCornerness << " " << point->mDetectionScale);
00477                 if((point->mX < borderIgnoreSize) ||
00478                    (point->mY < borderIgnoreSize) ||
00479                    (point->mX >= imIntensity->CW() - borderIgnoreSize) ||
00480                    (point->mY >= imIntensity->CH() - borderIgnoreSize)) 
00481                 {
00482                     //ILOG_DEBUG("   " << point->mX << " " << point->mY << " BORDER CLOSENESS REJECT");
00483                     continue;
00484                 }
00485                 centroids.push_back(point);
00486             }
00487             ILOG_DEBUG(sigmaN << " " << pointList.size());
00488         }
00489         int info_harrisCount = centroids.size();
00490         String info_harrisTiming = timer.SplitTimeStr();
00491         
00492         // Laplacian scale selection
00493         laplacianScaleSelection(output, imIntensity, centroids, laplaceThreshold);
00494     
00495         delete imIntensity;
00496     
00497         ILOG_INFO("Harris found " << info_harrisCount << " (" << info_harrisTiming << "); Laplacian left " << output->Size() << " (" << timer.SplitTimeStr() << ")");
00498         
00499         // now sort the points by cornerness
00500         SortOnColumn5(output, false);
00501         return output;
00502     }
00503     
00504     ILOG_VAR_DEC;
00505 };
00506 
00507 ILOG_VAR_INIT(HarrisLaplaceDetector, Core.Feature);
00508 
00509 } // namespace Feature
00510 } // namespace Core
00511 } // namespace Impala
00512 
00513 #endif

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