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

Sift.h

Go to the documentation of this file.
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         //The window size taken for the desccriptor
00052         mDescriptorWindowSize=options.GetInt("dws",16);
00053         //Default is 8 bins from every region
00054         mDescriptorBinCount=options.GetInt("dbc",8);
00055         //Default is a 4x4 region
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         //For every level, construct the gradient magnitude and angle map
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                 //dd stands for derivative distance..
00129                 int dd;
00130                 //The sigma to be calculated in the gradient comes from 
00131                 //the difference of gaussians, for which peaks are analysed
00132                 //in the sigma neighborhood. because of these two shifts, we
00133                 //have to use l+2
00134                 Real64 sigma=mOctaves->GetSigma(o,l+2);
00136                 // If resampling is enabled, we have already reduced 
00137                 // the scale by two at every octave(doubling of sigma). 
00138                 // Therefore the derivative is the immediate neighbors.
00139                 //
00140                 // Otherwise jump as much as 1 sigma for a derivative,
00141                 // since the images are not scaled down as well.
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                     //this is the first derivative wrt. x
00150                     //[ -1 0 1 ]
00151                     G[0] = L->Value(i+dd,j) - L->Value(i-dd,j);
00152 
00153                     //this is the first derivative wrt. y
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                 ILOG_DEBUG("Octave("<<o<<","<<l<<") : ("
00165                             <<PixMin( mGradMag[o*mLevels+l]) <<","
00166                             <<PixMax( mGradMag[o*mLevels+l]) <<") ("
00167                             <<PixMin( mGradAng[o*mLevels+l]) <<","
00168                             <<PixMax( mGradAng[o*mLevels+l]) <<")");*/
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                 ILOG_DEBUG("Gaussian Created");
00195                 ILOG_DEBUG("sigmas = ( "<<sigma<<" , "<<sigma*1.5<<" )");
00196                 ILOG_DEBUG("sizes  = ( "<<mGaussians[index]->CW()<<" x "
00197                                         <<mGaussians[index]->CH()<<" )");
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             //Weight the gradient magnitudes with a gaussian,
00229             // with a sigma 1.5 times the original,
00230             // and centered around the keypoint
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             //Find the maximum in the histogram
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             //Update the Orientation of the keypoint to max_bin
00270             double low,high;
00271             low=-PI/2+incr*max_bin;
00272             high=-PI/2+incr*(max_bin+1);
00273             //ILOG_DEBUG("Orientation("<<max_bin<<"):"<<histAng[max_bin]
00274             //        <<" Values btw "<<low<<"-"<<high);
00275 
00277             //Find other values which are greater than 80% of highest peak
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                     //Check if it is a peak
00287                     if((histAng[b]>histAng[b-1])&&(histAng[b]>histAng[b+1])){
00288                         //Create a new keypoint at the same location 
00289                         //with this orientation
00290                         //
00291                         //ILOG_DEBUG("Create New Keypoint With Orientation:"<<b<<"-"<<histAng[b]);
00292                         mKeyPoints->Add(sigma,i,j,o,l,-PI/2+incr*(b+.5));
00293                     }
00294                 }
00295             }
00297             //find 3 histogram values closest to each peak, and fit a parabola
00298             //for better accuracy
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                 //Weight the gradient magnitudes with a gaussian,
00338                 // with a sigma 1.5 * descriptor window size
00339                 // and centered around the keypoint
00340 
00341                 
00342                 //Rotate
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                 //mHistogram Bin Count
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++){//hx and hy are divs
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                         //The descriptor is stored as 4x4 regions, and 8
00406                         //histogram bins
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                 //the size of the feature depends on the number of binws in the
00420                 //histograms, and the square of the region( default:8bins-4 x 4)
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 }}}//Namespace
00442 
00443 
00444 
00445 #endif
00446 
00447 

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