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
00043 Real64 mPrecision;
00044 Real64 mSigmaA;
00045 bool mUseRecGauss;
00046 bool mBackwardsCompatible;
00047
00048 HarrisLaplaceDetector(bool useRecGauss=false) :
00049 mPrecision(5.0),
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
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);
00117 Mul(tmp1, tmp1, src);
00118 Real64 theMax = PixMax(tmp1);
00119
00120
00121 ExportPoints expPoints(pListBI, harrisThreshold);
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
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
00149 Array2dScalarReal64* Lx2 = 0;
00150 Mul(Lx2, Lx, Lx);
00151 MulVal(Lx2, Lx2, sigmaDiff * sigmaDiff);
00152
00153 Array2dScalarReal64* Ly2 = 0;
00154 Mul(Ly2, Ly, Ly);
00155 MulVal(Ly2, Ly2, sigmaDiff * sigmaDiff);
00156
00157 Array2dScalarReal64* LxLy = 0;
00158 Mul(LxLy, Lx, Ly);
00159 MulVal(LxLy, LxLy, sigmaDiff * sigmaDiff);
00160
00161 delete Lx;
00162 delete Ly;
00163
00164
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
00176
00177
00178
00179
00180
00181
00182
00183
00184 delete harrisOutput;
00185 }
00186
00187
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
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
00220 Array2dScalarReal64* Lx2 = 0;
00221 Mul(Lx2, Lx, Lx);
00222 MulVal(Lx2, Lx2, sigmaDiff * sigmaDiff);
00223
00224 Array2dScalarReal64* Ly2 = 0;
00225 Mul(Ly2, Ly, Ly);
00226 MulVal(Ly2, Ly2, sigmaDiff * sigmaDiff);
00227
00228 Array2dScalarReal64* LxLy = 0;
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
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
00259
00260
00261
00262
00263
00264
00265
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
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
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
00323 for(int i = 0; i < precomputeScales.size(); i++) {
00324 if((i >= nearestIndex - 4) && (i <= nearestIndex + 4)) {
00325 interestingScales.push_back(i);
00326
00327 laplacianValues.push_back(cache[i]->Value(point->mX, point->mY));
00328
00329 }
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
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
00397 Array2dVec3Real64* imBoosted = 0;
00398 BoostImage(imBoosted, input, 0.065, 0.850, 0.524);
00399
00402
00403
00404
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
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
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
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
00456 Array2dScalarReal64* imIntensity = 0;
00457 RGB2Gray(imIntensity, input);
00458
00459
00460 MulVal(imIntensity, imIntensity, 1 / 255.0);
00461
00462
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
00477 if((point->mX < borderIgnoreSize) ||
00478 (point->mY < borderIgnoreSize) ||
00479 (point->mX >= imIntensity->CW() - borderIgnoreSize) ||
00480 (point->mY >= imIntensity->CH() - borderIgnoreSize))
00481 {
00482
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
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
00500 SortOnColumn5(output, false);
00501 return output;
00502 }
00503
00504 ILOG_VAR_DEC;
00505 };
00506
00507 ILOG_VAR_INIT(HarrisLaplaceDetector, Core.Feature);
00508
00509 }
00510 }
00511 }
00512
00513 #endif