SiftPyramid.cpp
Go to the documentation of this file.
00001 
00002 //      File:           SiftPyramid.cpp
00003 //      Author:         Changchang Wu
00004 //      Description :   Implementation of the SiftPyramid class.
00005 //                                      
00006 //
00007 //
00008 //      Copyright (c) 2007 University of North Carolina at Chapel Hill
00009 //      All Rights Reserved
00010 //
00011 //      Permission to use, copy, modify and distribute this software and its
00012 //      documentation for educational, research and non-profit purposes, without
00013 //      fee, and without a written agreement is hereby granted, provided that the
00014 //      above copyright notice and the following paragraph appear in all copies.        
00015 //
00016 //      The University of North Carolina at Chapel Hill make no representations
00017 //      about the suitability of this software for any purpose. It is provided
00018 //      'as is' without express or implied warranty. 
00019 //
00020 //      Please send BUG REPORTS to ccwu@cs.unc.edu
00021 //
00023 
00024 
00025 #include "GL/glew.h"
00026 #include <string.h>
00027 #include <iostream>
00028 #include <iomanip>
00029 #include <vector>
00030 #include <algorithm>
00031 #include <fstream>
00032 #include <math.h>
00033 using namespace std;
00034 
00035 #include "GlobalUtil.h"
00036 #include "SiftPyramid.h"
00037 #include "SiftGPU.h"
00038 
00039 
00040 #ifdef DEBUG_SIFTGPU
00041 #include "IL/il.h"
00042 #include "direct.h"
00043 #include "io.h"
00044 #include <sys/stat.h> 
00045 #endif
00046 
00047 
00048 
00049 void SiftPyramid::RunSIFT(GLTexInput*input)
00050 {
00051     CleanupBeforeSIFT(); 
00052 
00053         if(_existing_keypoints & SIFT_SKIP_FILTERING)
00054         {
00055                 
00056         }else
00057         {
00058                 GlobalUtil::StartTimer("Build    Pyramid");
00059                 BuildPyramid(input);
00060                 GlobalUtil::StopTimer();
00061                 _timing[0] = GetElapsedTime();
00062         }
00063 
00064 
00065         if(_existing_keypoints)
00066         {
00067                 //existing keypoint list should at least have the locations and scale
00068                 GlobalUtil::StartTimer("Upload Feature List");
00069                 if(!(_existing_keypoints & SIFT_SKIP_FILTERING)) ComputeGradient();
00070                 GenerateFeatureListTex();
00071                 GlobalUtil::StopTimer();
00072                 _timing[2] = GetElapsedTime();
00073         }else
00074         {
00075 
00076                 GlobalUtil::StartTimer("Detect Keypoints");
00077                 DetectKeypointsEX();
00078                 GlobalUtil::StopTimer();
00079                 _timing[1] = GetElapsedTime();
00080 
00081                 if(GlobalUtil::_ListGenGPU ==1)
00082                 {
00083                         GlobalUtil::StartTimer("Get Feature List");
00084                         GenerateFeatureList();
00085                         GlobalUtil::StopTimer();
00086 
00087                 }else
00088                 {
00089                         GlobalUtil::StartTimer("Transfer Feature List");
00090                         GenerateFeatureListCPU();
00091                         GlobalUtil::StopTimer();
00092                 }
00093             LimitFeatureCount(0);
00094                 _timing[2] = GetElapsedTime();
00095         }
00096 
00097 
00098         
00099         if(_existing_keypoints& SIFT_SKIP_ORIENTATION)
00100         {
00101                 //use exisitng feature orientation or
00102         }else   if(GlobalUtil::_MaxOrientation>0)
00103         {
00104                 //some extra tricks are done to handle existing keypoint list
00105                 GlobalUtil::StartTimer("Feature Orientations");
00106                 GetFeatureOrientations();
00107                 GlobalUtil::StopTimer();
00108                 _timing[3] = GetElapsedTime();
00109 
00110                 //for existing keypoint list, only the strongest orientation is kept.
00111                 if(GlobalUtil::_MaxOrientation >1 && !_existing_keypoints && !GlobalUtil::_FixedOrientation)
00112                 {
00113                         GlobalUtil::StartTimer("MultiO Feature List");
00114                         ReshapeFeatureListCPU();
00115             LimitFeatureCount(1);
00116                         GlobalUtil::StopTimer();        
00117                         _timing[4] = GetElapsedTime();
00118                 }
00119         }else
00120         {
00121                 GlobalUtil::StartTimer("Feature Orientations");
00122                 GetSimplifiedOrientation();
00123                 GlobalUtil::StopTimer();
00124                 _timing[3] = GetElapsedTime();
00125         }
00126 
00127         PrepareBuffer();
00128 
00129         if(_existing_keypoints & SIFT_SKIP_ORIENTATION)
00130         {
00131                 //no need to read back feature if all fields of keypoints are already specified
00132         }else
00133         {
00134                 GlobalUtil::StartTimer("Download Keypoints");
00135 #ifdef NO_DUPLICATE_DOWNLOAD
00136                 if(GlobalUtil::_MaxOrientation < 2 || GlobalUtil::_FixedOrientation)
00137 #endif
00138                 DownloadKeypoints();
00139                 GlobalUtil::StopTimer();
00140                 _timing[5] =  GetElapsedTime(); 
00141         }
00142 
00143 
00144 
00145         if(GlobalUtil::_DescriptorPPT)
00146         {
00147                 //desciprotrs are downloaded in descriptor computation of each level
00148                 GlobalUtil::StartTimer("Get Descriptor");
00149                 GetFeatureDescriptors();
00150                 GlobalUtil::StopTimer();
00151                 _timing[6] =  GetElapsedTime(); 
00152         }
00153 
00154         //reset the existing keypoints
00155         _existing_keypoints = 0;
00156         _keypoint_index.resize(0);
00157 
00158     if(GlobalUtil::_UseSiftGPUEX)
00159         {
00160                 GlobalUtil::StartTimer("Gen. Display VBO");
00161                 GenerateFeatureDisplayVBO();
00162                 GlobalUtil::StopTimer();
00163                 _timing[7] = GlobalUtil::GetElapsedTime();
00164         }
00165     //clean up
00166     CleanUpAfterSIFT();
00167 }
00168 
00169 
00170 void SiftPyramid::LimitFeatureCount(int have_keylist)
00171 {
00172 
00173         if(GlobalUtil::_FeatureCountThreshold <= 0 || _existing_keypoints) return;
00175         //skip the lowest levels to reduce number of features. 
00176 
00177     if(GlobalUtil::_TruncateMethod == 2)
00178     {
00179         int i = 0, new_feature_num = 0, level_num = param._dog_level_num * _octave_num;
00180         for(; new_feature_num < _FeatureCountThreshold && i < level_num; ++i) new_feature_num += _levelFeatureNum[i];
00181         for(; i < level_num; ++i)            _levelFeatureNum[i] = 0; 
00182 
00183         if(new_feature_num < _featureNum)
00184         {
00185             _featureNum = new_feature_num;
00186             if(GlobalUtil::_verbose )
00187             {
00188                     std::cout<<"#Features Reduced:\t"<<_featureNum<<endl;
00189             }
00190         }
00191     }else
00192     {
00193         int i = 0, num_to_erase = 0;
00194         while(_featureNum - _levelFeatureNum[i] > _FeatureCountThreshold)
00195         {
00196             num_to_erase += _levelFeatureNum[i];
00197                 _featureNum -= _levelFeatureNum[i];
00198                 _levelFeatureNum[i++] = 0;
00199         }
00200         if(num_to_erase > 0 && have_keylist)
00201         {
00202             _keypoint_buffer.erase(_keypoint_buffer.begin(), _keypoint_buffer.begin() + num_to_erase * 4);
00203         }
00204         if(GlobalUtil::_verbose &&  num_to_erase > 0)
00205         {
00206                 std::cout<<"#Features Reduced:\t"<<_featureNum<<endl;
00207         }
00208     }
00209 
00210 
00211 }
00212 
00213 void SiftPyramid::PrepareBuffer()
00214 {
00215         //when there is no existing keypoint list, the feature list need to be downloaded
00216         //when an existing keypoint list does not have orientaiton, we need to download them again.
00217         if(!(_existing_keypoints & SIFT_SKIP_ORIENTATION)) 
00218         {
00219                 //_keypoint_buffer.resize(4 * (_featureNum +align));
00220                 _keypoint_buffer.resize(4 * (_featureNum + GlobalUtil::_texMaxDim)); //11/19/2008
00221         }
00222         if(GlobalUtil::_DescriptorPPT)
00223         {
00224                 //_descriptor_buffer.resize(128*(_featureNum + align)); 
00225                 _descriptor_buffer.resize(128 * _featureNum + 16 * GlobalUtil::_texMaxDim);//11/19/2008
00226         }
00227 
00228 }
00229 
00230 int SiftPyramid:: GetRequiredOctaveNum(int inputsz)
00231 {
00232     //[2 ^ i,  2 ^ (i + 1)) -> i - 3...
00233     //768 in [2^9, 2^10)  -> 6 -> smallest will be 768 / 32 = 24
00234     int num =  (int) floor (log ( inputsz * 2.0 / GlobalUtil::_texMinDim )/log(2.0));
00235     return num <= 0 ? 1 : num; 
00236 }
00237 
00238 void SiftPyramid::CopyFeatureVector(float*keys, float *descriptors)
00239 {
00240         if(keys)                memcpy(keys, &_keypoint_buffer[0], 4*_featureNum*sizeof(float));
00241         if(descriptors) memcpy(descriptors, &_descriptor_buffer[0], 128*_featureNum*sizeof(float));
00242 }
00243 
00244 void SiftPyramid:: SetKeypointList(int num, const float * keys, int run_on_current, int skip_orientation)
00245 {
00246         //for each input keypoint
00247         //sort the key point list by size, and assign them to corresponding levels
00248         if(num <=0) return;
00249         _featureNum = num;
00251         _keypoint_buffer.resize(num * 4);
00252         memcpy(&_keypoint_buffer[0], keys, 4 * num * sizeof(float));
00253         //location and scale can be skipped
00254         _existing_keypoints = SIFT_SKIP_DETECTION;
00255         //filtering is skipped if it is running on the same image
00256         if(run_on_current) _existing_keypoints |= SIFT_SKIP_FILTERING;
00257         //orientation can be skipped if specified
00258         if(skip_orientation) _existing_keypoints |= SIFT_SKIP_ORIENTATION;
00259     //hacking parameter for using rectangle description mode
00260     if(skip_orientation == -1) _existing_keypoints |= SIFT_RECT_DESCRIPTION;
00261 }
00262 
00263 
00264 void SiftPyramid::SaveSIFT(const char * szFileName)
00265 {
00266         if (_featureNum <=0) return;
00267         float * pk = &_keypoint_buffer[0];
00268 
00269         if(GlobalUtil::_BinarySIFT)
00270         {
00271                 std::ofstream out(szFileName, ios::binary);
00272                 out.write((char* )(&_featureNum), sizeof(int));
00273 
00274                 if(GlobalUtil::_DescriptorPPT)
00275                 {
00276                         int dim = 128;
00277                         out.write((char* )(&dim), sizeof(int));
00278                         float * pd = &_descriptor_buffer[0] ;
00279                         for(int i = 0; i < _featureNum; i++, pk+=4, pd +=128)
00280                         {
00281                                 out.write((char* )(pk +1), sizeof(float));
00282                                 out.write((char* )(pk), sizeof(float));
00283                                 out.write((char* )(pk+2), 2 * sizeof(float));
00284                                 out.write((char* )(pd), 128 * sizeof(float));
00285                         }
00286                 }else
00287                 {
00288                         int dim = 0;
00289                         out.write((char* )(&dim), sizeof(int));
00290                         for(int i = 0; i < _featureNum; i++, pk+=4)
00291                         {
00292                                 out.write((char* )(pk +1), sizeof(float));
00293                                 out.write((char* )(pk), sizeof(float));
00294                                 out.write((char* )(pk+2), 2 * sizeof(float));
00295                         }
00296                 }
00297         }else
00298         {
00299                 std::ofstream out(szFileName);
00300                 out.flags(ios::fixed);
00301 
00302                 if(GlobalUtil::_DescriptorPPT)
00303                 {
00304                         float * pd = &_descriptor_buffer[0] ;
00305                         out<<_featureNum<<" 128"<<endl;
00306 
00307                         for(int i = 0; i < _featureNum; i++)
00308                         {
00309                                 //in y, x, scale, orientation order
00310                                 out<<setprecision(2) << pk[1]<<" "<<setprecision(2) << pk[0]<<" "
00311                                         <<setprecision(3) << pk[2]<<" " <<setprecision(3) <<  pk[3]<< endl; 
00312 
00314                                 pk+=4;
00315                                 for(int k = 0; k < 128; k ++, pd++) 
00316                                 {
00317                                         if(GlobalUtil::_NormalizedSIFT)
00318                                                 out<< ((unsigned int)floor(0.5+512.0f*(*pd)))<<" ";
00319                                         else
00320                                                 out << setprecision(8) << pd[0] << " ";
00321 
00322                                         if ( (k+1)%20 == 0 ) out<<endl; //suggested by Martin Schneider
00323 
00324                                 }
00325                                 out<<endl;
00326 
00327                         }
00328                 
00329                 }else
00330                 {
00331                         out<<_featureNum<<" 0"<<endl;
00332                         for(int i = 0; i < _featureNum; i++, pk+=4)
00333                         {
00334                                 out<<pk[1]<<" "<<pk[0]<<" "<<pk[2]<<" " << pk[3]<<endl;
00335                         }
00336                 }
00337         }
00338 }
00339 
00340 #ifdef DEBUG_SIFTGPU
00341 void SiftPyramid::BeginDEBUG(const char *imagepath)
00342 {
00343         if(imagepath && imagepath[0])
00344         {
00345                 strcpy(_debug_path, imagepath);
00346                 strcat(_debug_path, ".debug");
00347         }else
00348         {
00349                 strcpy(_debug_path, ".debug");
00350         }
00351 
00352         mkdir(_debug_path);
00353         chmod(_debug_path, _S_IREAD | _S_IWRITE);
00354 }
00355 
00356 void SiftPyramid::StopDEBUG()
00357 {
00358         _debug_path[0] = 0;
00359 }
00360 
00361 
00362 void SiftPyramid::WriteTextureForDEBUG(GLTexImage * tex, const char *namet, ...)
00363 {
00364         char name[_MAX_PATH];
00365         char * p = name, * ps = _debug_path;
00366         while(*ps) *p++ = *ps ++;
00367         *p++ = '/';
00368         va_list marker;
00369         va_start(marker, namet);
00370         vsprintf(p, namet, marker);
00371         va_end(marker);
00372         unsigned int imID;
00373         int width = tex->GetImgWidth();
00374         int height = tex->GetImgHeight();
00375         float* buffer1 = new float[ width * height  * 4];
00376         float* buffer2 = new float[ width * height  * 4];
00377 
00378         //read data back
00379         glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
00380         tex->AttachToFBO(0);
00381         tex->FitTexViewPort();
00382         glReadPixels(0, 0, width, height, GL_RGBA , GL_FLOAT, buffer1);
00383 
00384         //Tiffs saved with IL are flipped
00385         for(int i = 0; i < height; i++)
00386         {
00387                 memcpy(buffer2 + i * width * 4, 
00388                         buffer1 + (height - i - 1) * width * 4,  
00389                         width * 4 * sizeof(float));
00390         }
00391 
00392         //save data as floating point tiff file
00393         ilGenImages(1, &imID);
00394         ilBindImage(imID); 
00395         ilEnable(IL_FILE_OVERWRITE);
00396         ilTexImage(width, height, 1, 4, IL_RGBA, IL_FLOAT, buffer2);
00397         ilSave(IL_TIF, name); 
00398         ilDeleteImages(1, &imID); 
00399 
00400         delete[] buffer1;
00401         delete[] buffer2;
00402         glReadBuffer(GL_NONE);
00403 }
00404 
00405 
00406 #endif


siftgpu
Author(s): Changchang Wu (library), Bence Magyar (ROS wrapper)
autogenerated on Thu Jan 2 2014 11:38:01