00001 #ifndef Impala_Core_Array_Sift_h
00002 #define Impala_Core_Array_Sift_h
00003
00004 #include "Core/Array/Octaves.h"
00005 #include "Core/Keypoint/DoG.h"
00006
00007
00008 namespace Impala{
00009 namespace Core{
00010 namespace KeyPoint{
00011
00012 class Sift{
00013
00014 private:
00015 ILOG_VAR_DEC;
00016 Array2dScalarUInt8* mSrc;
00017 Detector* mDetector;
00018 DetectorType mDetectorType;
00019 Array2dScalarReal64** mGradMag;
00020 Array2dScalarReal64** mGradAng;
00021 Array2dScalarReal64** mGaussians;
00022 Array2dScalarReal64* mGaussian;
00023 KeyPointTableType* mKeyPoints;
00024 FeatureTable* mFeatureTable;
00025 int mLevelCnt;
00026 int mOctaveCnt;
00027 int mDescriptorWindowSize;
00028 int mDescriptorBinCount;
00029 int mDescriptorRegDiv;
00030 int mDescriptorLength;
00031
00032 Octaves* mOctaves;
00033 public:
00034
00035
00036 Sift(Array2dScalarUInt8* src, int Octaves, int Levels, KeyPoint::DetectorType dT = DOG )
00037 :mSrc(src)
00038 {
00039 mDetectorType = dT;
00040 Init();
00041 }
00042 Octaves* GetOctaves(){
00043 return mOctaves;
00044 }
00045 Detector* GetDetector(){
00046 return mDetector;
00047 }
00048
00049 void Init(){
00050 CmdOptions& options = CmdOptions::GetInstance();
00051
00052 mDescriptorWindowSize=options.GetInt("dws",16);
00053
00054 mDescriptorBinCount=options.GetInt("dbc",8);
00055
00056 mDescriptorRegDiv=options.GetInt("drv",4);
00057 ILOG_INFO("Descriptor Window Size : "<<mDescriptorWindowSize);
00058 ILOG_INFO("Descriptor Histogram Bin Count : "<<mDescriptorBinCount);
00059
00060 mDescriptorLength = mDescriptorBinCount *
00061 mDescriptorRegDiv * mDescriptorRegDiv;
00062
00063
00064 mOctaves = new Impala::Core::Array::Octaves(mSrc,-1,3);
00065 switch(mDetectorType){
00066 case DOG:
00067 mDetector = new DoG(mOctaves);
00068 }
00069 mDetector->FindKeyPoints();
00070 mLevelCnt = mOctaves->GetLevelCount();
00071 mOctaveCnt = mOctaves->GetOctaveCount();
00072
00073
00074 mGradMag = new Array2dScalarReal64*[mOctaveCnt*mLevelCnt];
00075 mGradAng = new Array2dScalarReal64*[mOctaveCnt*mLevelCnt];
00076 mGaussians = new Array2dScalarReal64*[mOctaveCnt*mLevelCnt];
00077 for(int i=0;i<mOctaveCnt*mLevelCnt;i++){
00078 mGaussians[i] =0;
00079 mGradMag[i] = 0;
00080 mGradAng[i] = 0;
00081 }
00082
00083 BuildGaussians();
00084 mGaussian = MakeGaussian2d( 1.5 * mDescriptorWindowSize,
00085 1.5 * mDescriptorWindowSize,0,0,3);
00086 mKeyPoints=new KeyPointTableType(0);
00087
00088 }
00089 void ExtractDescriptors()
00090 {
00091 ComputeGradientField();
00092 AssignOrientation();
00093 Extract();
00094 }
00095
00096 Array2dScalarReal64* GetGradMag(int o,int l)
00097 {
00098 if(l>mLevelCnt-1){
00099 ILOG_INFO("Clipping, only "<<mLevelCnt<< " gradmag. at each octave!");
00100 l=mLevelCnt-1;
00101 }
00102 return mGradMag[o*mLevelCnt+l];
00103 }
00104
00105 Array2dScalarReal64* GetGradAng(int o,int l)
00106 {
00107 if(l>mLevelCnt-1){
00108 ILOG_INFO("Clipping, only "<<mLevelCnt<< " gradang. at each octave!");
00109 l=mLevelCnt-1;
00110 }
00111 return mGradAng[o*mLevelCnt+l];
00112 }
00113 void ComputeGradientField(){
00114 double H[4];
00115 double G[2];
00116 double S[2];
00117
00118 ILOG_INFO("Computing gradient field");
00119
00120
00121 for(int o=0;o<mOctaveCnt;o++){
00122 for(int l=0;l<mLevelCnt;l++)
00123 {
00124 Array2dScalarReal64* L = mOctaves->GetOctave(o,l);
00125 Set(mGradMag[o*mLevelCnt+l],L);
00126 SetVal(mGradMag[o*mLevelCnt+l],0);
00127 Set(mGradAng[o*mLevelCnt+l],mGradMag[o*mLevelCnt+l]);
00128
00129 int dd;
00130
00131
00132
00133
00134 Real64 sigma=mOctaves->GetSigma(o,l+2);
00136
00137
00138
00139
00140
00141
00142 if(mOctaves->IsResamplingEnabled())
00143 dd=1;
00144 else
00145 dd=sigma;
00146
00147 for(int i=dd;i<L->CW()-dd;i++){
00148 for(int j=dd;j<L->CH()-dd;j++){
00149
00150
00151 G[0] = L->Value(i+dd,j) - L->Value(i-dd,j);
00152
00153
00154 G[1] = L->Value(i,j+dd) - L->Value(i,j-dd);
00155
00156 mGradMag[o*mLevelCnt+l]->SetValue(sqrt(G[0]*G[0]+G[1]*G[1])
00157 ,i,j);
00158 mGradAng[o*mLevelCnt+l]->SetValue(atan(G[1]/G[0]),i,j);
00159
00160
00161 }
00162 }
00163
00164
00165
00166
00167
00168
00169 Normalize(mGradMag[o*mLevelCnt+l]);
00170
00171 }
00172 }
00173 }
00174 void Normalize(Array2dScalarReal64* s){
00175 Real64 min,max;
00176 PixMinMax(s,&min,&max);
00177 AddVal(s,s,-min);
00178 MulVal(s,s,1/(max-min));
00179 }
00180
00181 void BuildGaussians(){
00182 Real64 sigma;
00183 int index;
00184 for (int o=0;o<mOctaveCnt;o++){
00185 for(int l=0;l<mLevelCnt;l++)
00186 {
00187 sigma = mOctaves->GetSigma(o,l+2);
00188 index = o*mLevelCnt+l;
00189
00190 mGaussians[index] = MakeGaussian2d(1.5 * sigma,
00191 1.5 * sigma,0,0,3);
00192 Normalize(mGaussians[index]);
00193
00194
00195
00196
00197
00198
00199
00200 }
00201
00202 }
00203 }
00204 void AssignOrientation()
00205 {
00206
00207 double sigma;
00208 int range=0;
00209 int k=0;
00210 int o,l,i,j,index;
00211 Array2dScalarReal64 *GA, *GM;
00212 Array2dScalarReal64 *Gaussian;
00213
00214 mKeyPoints=mDetector->GetKeyPoints();
00215 int OrigSize = mKeyPoints->Size();
00216 while(k<OrigSize)
00217 {
00218 sigma= mKeyPoints->Get1(k);
00219 i = mKeyPoints->Get2(k);
00220 j = mKeyPoints->Get3(k);
00221 o = mKeyPoints->Get4(k);
00222 l = mKeyPoints->Get5(k);
00223 index=o*mLevelCnt+l;
00224
00225 GA=mGradAng[index];
00226 GM=mGradMag[index];
00227 Gaussian=mGaussians[index];
00228
00229
00230
00231 range = Gaussian->CW()/2;
00232
00233 double histAng[36];
00234 for(int h=0;h<36;h++)
00235 histAng[h]=0;
00236 double incr=PI/36;
00237
00238 for(int x=-range;x<range+1;x++)
00239 {
00240 for(int y=-range;y<range+1;y++)
00241 {
00242 if((i+x<0)||(i+x>GA->CW())||
00243 (j+y<0)||(j+y>GA->CH()))
00244 continue;
00245 if((x+range>=Gaussian->CW()||y+range>=Gaussian->CH()))
00246 continue;
00247 int bin=floor(18+GA->Value(i+x,j+y)/incr);
00248 if(bin>36)
00249 continue;
00250 histAng[bin]+=Gaussian->Value(x+range,y+range) *
00251 GM->Value(i+x,j+y);
00252 }
00253
00254 }
00256
00257 double max_val=0;
00258 int max_bin=0;
00259 for(int b=0;b<36;b++)
00260 {
00261 if(histAng[b]>max_val)
00262 {
00263 max_val = histAng[b];
00264 max_bin=b;
00265 }
00266 }
00267 mKeyPoints->Set6(k,-PI/2+incr*(max_bin+.5));
00269
00270 double low,high;
00271 low=-PI/2+incr*max_bin;
00272 high=-PI/2+incr*(max_bin+1);
00273
00274
00275
00277
00278 double max80= .8 * max_val;
00279 for(int b=1;b<35;b++)
00280 {
00281 if(b==max_bin)
00282 continue;
00283 if(histAng[b]>max80)
00284 {
00286
00287 if((histAng[b]>histAng[b-1])&&(histAng[b]>histAng[b+1])){
00288
00289
00290
00291
00292 mKeyPoints->Add(sigma,i,j,o,l,-PI/2+incr*(b+.5));
00293 }
00294 }
00295 }
00297
00298
00299
00300 k++;
00301 }
00302 ILOG_INFO("Total "<<mKeyPoints->Size()-OrigSize
00303 <<" new orientations assigned!");
00304 return;
00305 }
00306 void Extract()
00307 {
00308 ILOG_DEBUG("Extracting Descriptors")
00309 int k=0;
00310
00311 Array2dScalarReal64 *GM,*GA,*Gaussian;
00312 int o,l,i,j,index;
00313 Real64 ori, sigma;
00314 int range = mGaussian->CW()/2;
00315 int range_ext= range*sqrt(2)+1;
00316 KeyPointTableType* oldKeyPoints=mKeyPoints;
00317 int size = oldKeyPoints->Size();
00318 int current = 0;
00319 mFeatureTable = new FeatureTable(FeatureDefinition("SIFT"),size,mDescriptorLength);
00320
00321
00322 mKeyPoints=new KeyPointTableType(0);
00323 while(k<size)
00324 {
00325 if(!((oldKeyPoints->Get2(k)==0)&&(oldKeyPoints->Get3(k)==0))){
00326 sigma= oldKeyPoints->Get1(k);
00327 i = oldKeyPoints->Get2(k);
00328 j = oldKeyPoints->Get3(k);
00329 o = oldKeyPoints->Get4(k);
00330 l = oldKeyPoints->Get5(k);
00331 ori = oldKeyPoints->Get6(k);
00332 index=o*mLevelCnt+l;
00333 mKeyPoints->Add(sigma,i,j,o,l,ori);
00334 GA=mGradAng[index];
00335 GM=mGradMag[index];
00336
00337
00338
00339
00340
00341
00342
00343 Array2dScalarReal64 *srcGA=ArrayCreate<Array2dScalarReal64>
00344 (mDescriptorWindowSize,mDescriptorWindowSize);
00345 Array2dScalarReal64 *srcGM=ArrayCreate<Array2dScalarReal64>
00346 (mDescriptorWindowSize,mDescriptorWindowSize);
00347 Array2dScalarReal64 *dstGA=0;
00348 Array2dScalarReal64 *dstGM=0;
00349 SetVal(srcGA,0);
00350 SetVal(srcGM,0);
00351
00352
00353
00354 double histAng[16*mDescriptorBinCount];
00355 for(int h=0;h<16*mDescriptorBinCount;h++)
00356 histAng[h]=0;
00357 double incr=PI/mDescriptorBinCount;
00358 bool clipped=false;
00359
00360 for(int x = -mDescriptorWindowSize/2;
00361 x < mDescriptorWindowSize/2; x++)
00362 {
00363 for(int y =-mDescriptorWindowSize/2;
00364 y <mDescriptorWindowSize/2; y++)
00365 {
00366 if((i+x<0)||(i+x>GA->CW())||
00367 (j+y<0)||(j+y>GA->CH())){
00368 clipped=true;
00369 continue;
00370 }
00371 srcGA->SetValue(GA->Value(i+x,j+y),
00372 x+mDescriptorWindowSize/2,
00373 y+mDescriptorWindowSize/2);
00374 srcGM->SetValue(GM->Value(i+x,j+y),
00375 x+mDescriptorWindowSize/2,
00376 y+mDescriptorWindowSize/2);
00377
00378 }
00379
00380 }
00381
00382 Rotate(dstGA,srcGA,ori*180/PI,Geometry::LINEAR,true,0);
00383 AddVal(dstGA,dstGA,ori);
00384
00385 Rotate(dstGM,srcGM,ori*180/PI,Geometry::LINEAR,true,0);
00386
00387 for(int hx=0;hx<mDescriptorRegDiv;hx++){
00388 for(int hy=0;hy<mDescriptorRegDiv;hy++){
00389 for(int ix=0;ix<dstGA->CW()/mDescriptorRegDiv;ix++){
00390 for(int iy=0;iy<dstGA->CH()/mDescriptorRegDiv;iy++){
00391 int x=hx*mDescriptorRegDiv+ix;
00392 int y=hy*mDescriptorRegDiv+iy;
00393 if(dstGA->Value(x,y)>PI/2)
00394 dstGA->SetValue(dstGA->Value(x,y)-PI/2,x,y);
00395 if(dstGA->Value(x,y)<0)
00396 dstGA->SetValue(dstGA->Value(x,y)+PI/2,x,y);
00397
00398 int bin=floor(mDescriptorBinCount/2+
00399 dstGA->Value(x,y)/incr);
00400
00401 if(bin>mDescriptorBinCount)
00402 continue;
00403 if(bin<0)
00404 continue;
00405
00406
00407
00408 histAng[mDescriptorRegDiv*mDescriptorBinCount*hx+
00409 mDescriptorBinCount*hy+
00410 bin]
00411 += mGaussian->Value(x,y) * dstGM->Value(x,y);
00412
00413 }
00414
00415 }
00416 }
00417 }
00418 mFeatureTable->GetColumn1()->Set(current++,MakeQuid(0,0,0,k));
00419
00420
00421 mFeatureTable->GetColumn2()->AddVector( histAng,
00422 mDescriptorLength );
00423
00424 }
00425 k++;
00426 }
00427 ILOG_INFO("Total Keypoint Count:"<<mKeyPoints->Size());
00428
00429
00430 }
00431 KeyPointTableType* GetKeypoints(){
00432 return mKeyPoints;
00433 }
00434
00435
00436
00437 };
00438
00439 ILOG_VAR_INIT(Sift, Impala.Core.Array);
00440
00441 }}}
00442
00443
00444
00445 #endif
00446
00447