PyramidCU.cpp
Go to the documentation of this file.
00001 
00002 //      File:           PyramidCU.cpp
00003 //      Author:         Changchang Wu
00004 //      Description : implementation of the PyramidCU class.
00005 //                              CUDA-based implementation of SiftPyramid
00006 //
00007 //      Copyright (c) 2007 University of North Carolina at Chapel Hill
00008 //      All Rights Reserved
00009 //
00010 //      Permission to use, copy, modify and distribute this software and its
00011 //      documentation for educational, research and non-profit purposes, without
00012 //      fee, and without a written agreement is hereby granted, provided that the
00013 //      above copyright notice and the following paragraph appear in all copies.
00014 //      
00015 //      The University of North Carolina at Chapel Hill make no representations
00016 //      about the suitability of this software for any purpose. It is provided
00017 //      'as is' without express or implied warranty. 
00018 //
00019 //      Please send BUG REPORTS to ccwu@cs.unc.edu
00020 //
00022 
00023 #if defined(CUDA_SIFTGPU_ENABLED)
00024 
00025 
00026 #include "GL/glew.h"
00027 #include <iostream>
00028 #include <vector>
00029 #include <algorithm>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <math.h>
00033 using namespace std;
00034 
00035 #include "GlobalUtil.h"
00036 #include "GLTexImage.h"
00037 #include "CuTexImage.h" 
00038 #include "SiftGPU.h"
00039 #include "SiftPyramid.h"
00040 #include "ProgramCU.h"
00041 #include "PyramidCU.h"
00042 
00043 
00044 //#include "imdebug/imdebuggl.h"
00045 //#pragma comment (lib, "../lib/imdebug.lib")
00046 
00047 
00048 
00049 #define USE_TIMING()            double t, t0, tt;
00050 #define OCTAVE_START()          if(GlobalUtil::_timingO){       t = t0 = CLOCK();       cout<<"#"<<i+_down_sample_factor<<"\t"; }
00051 #define LEVEL_FINISH()          if(GlobalUtil::_timingL){       ProgramCU::FinishCUDA();        tt = CLOCK();cout<<(tt-t)<<"\t";        t = CLOCK();}
00052 #define OCTAVE_FINISH()         if(GlobalUtil::_timingO)cout<<"|\t"<<(CLOCK()-t0)<<endl;
00053 
00054 
00055 PyramidCU::PyramidCU(SiftParam& sp) : SiftPyramid(sp)
00056 {
00057         _allPyramid = NULL;
00058         _histoPyramidTex = NULL;
00059         _featureTex = NULL;
00060         _descriptorTex = NULL;
00061         _orientationTex = NULL;
00062         _bufferPBO = 0;
00063     _bufferTEX = NULL;
00064         _inputTex = new CuTexImage();
00065 
00067     InitializeContext();
00068 }
00069 
00070 PyramidCU::~PyramidCU()
00071 {
00072         DestroyPerLevelData();
00073         DestroySharedData();
00074         DestroyPyramidData();
00075         if(_inputTex) delete _inputTex;
00076     if(_bufferPBO) glDeleteBuffers(1, &_bufferPBO);
00077     if(_bufferTEX) delete _bufferTEX;
00078 }
00079 
00080 void PyramidCU::InitializeContext()
00081 {
00082     GlobalUtil::InitGLParam(1);
00083     GlobalUtil::_GoodOpenGL = max(GlobalUtil::_GoodOpenGL, 1); 
00084 }
00085 
00086 void PyramidCU::InitPyramid(int w, int h, int ds)
00087 {
00088         int wp, hp, toobig = 0;
00089         if(ds == 0)
00090         {
00091                 //
00092                 TruncateWidth(w);
00094                 _down_sample_factor = 0;
00095                 if(GlobalUtil::_octave_min_default>=0)
00096                 {
00097                         wp = w >> _octave_min_default;
00098                         hp = h >> _octave_min_default;
00099                 }else
00100                 {
00101                         //can't upsample by more than 8
00102                         _octave_min_default = max(-3, _octave_min_default);
00103                         //
00104                         wp = w << (-_octave_min_default);
00105                         hp = h << (-_octave_min_default);
00106                 }
00107                 _octave_min = _octave_min_default;
00108         }else
00109         {
00110                 //must use 0 as _octave_min; 
00111                 _octave_min = 0;
00112                 _down_sample_factor = ds;
00113                 w >>= ds;
00114                 h >>= ds;
00116 
00117                 TruncateWidth(w);
00118 
00119                 wp = w;
00120                 hp = h; 
00121 
00122         }
00123 
00124         while(wp > GlobalUtil::_texMaxDim  || hp > GlobalUtil::_texMaxDim )
00125         {
00126                 _octave_min ++;
00127                 wp >>= 1;
00128                 hp >>= 1;
00129                 toobig = 1;
00130         }
00131 
00132         while(GlobalUtil::_MemCapGPU > 0 && GlobalUtil::_FitMemoryCap &&  (wp >_pyramid_width || hp > _pyramid_height)&& 
00133                 max(max(wp, hp), max(_pyramid_width, _pyramid_height)) >  1024 * sqrt(GlobalUtil::_MemCapGPU / 110.0))
00134         {
00135                 _octave_min ++;
00136                 wp >>= 1;
00137                 hp >>= 1;
00138                 toobig = 2;
00139         }
00140 
00141 
00142         if(toobig && GlobalUtil::_verbose && _octave_min > 0)
00143         {
00144                 std::cout<<(toobig == 2 ? "[**SKIP OCTAVES**]:\tExceeding Memory Cap (-nomc)\n" :
00145                                         "[**SKIP OCTAVES**]:\tReaching the dimension limit(-maxd)!\n");
00146         }
00147         //ResizePyramid(wp, hp);
00148         if( wp == _pyramid_width && hp == _pyramid_height && _allocated )
00149         {
00150                 FitPyramid(wp, hp);
00151         }else if(GlobalUtil::_ForceTightPyramid || _allocated ==0)
00152         {
00153                 ResizePyramid(wp, hp);
00154         }
00155         else if( wp > _pyramid_width || hp > _pyramid_height )
00156         {
00157                 ResizePyramid(max(wp, _pyramid_width), max(hp, _pyramid_height));
00158                 if(wp < _pyramid_width || hp < _pyramid_height)  FitPyramid(wp, hp);
00159         }
00160         else
00161         {
00162                 //try use the pyramid allocated for large image on small input images
00163                 FitPyramid(wp, hp);
00164         }
00165 }
00166 
00167 void PyramidCU::ResizePyramid(int w, int h)
00168 {
00169         //
00170         unsigned int totalkb = 0;
00171         int _octave_num_new, input_sz, i, j;
00172         //
00173 
00174         if(_pyramid_width == w && _pyramid_height == h && _allocated) return;
00175 
00176         if(w > GlobalUtil::_texMaxDim || h > GlobalUtil::_texMaxDim) return ;
00177 
00178         if(GlobalUtil::_verbose && GlobalUtil::_timingS) std::cout<<"[Allocate Pyramid]:\t" <<w<<"x"<<h<<endl;
00179         //first octave does not change
00180         _pyramid_octave_first = 0;
00181 
00182         
00183         //compute # of octaves
00184 
00185         input_sz = min(w,h) ;
00186         _pyramid_width =  w;
00187         _pyramid_height =  h;
00188 
00189 
00190 
00191         //reset to preset parameters
00192 
00193         _octave_num_new  = GlobalUtil::_octave_num_default;
00194 
00195         if(_octave_num_new < 1) 
00196         {
00197                 _octave_num_new = (int) floor (log ( double(input_sz))/log(2.0)) -3 ;
00198                 if(_octave_num_new<1 ) _octave_num_new = 1;
00199         }
00200 
00201         if(_pyramid_octave_num != _octave_num_new)
00202         {
00203                 //destroy the original pyramid if the # of octave changes
00204                 if(_octave_num >0) 
00205                 {
00206                         DestroyPerLevelData();
00207                         DestroyPyramidData();
00208                 }
00209                 _pyramid_octave_num = _octave_num_new;
00210         }
00211 
00212         _octave_num = _pyramid_octave_num;
00213 
00214         int noct = _octave_num;
00215         int nlev = param._level_num;
00216 
00217         //      //initialize the pyramid
00218         if(_allPyramid==NULL)   _allPyramid = new CuTexImage[ noct* nlev * DATA_NUM];
00219 
00220         CuTexImage * gus =  GetBaseLevel(_octave_min, DATA_GAUSSIAN);
00221         CuTexImage * dog =  GetBaseLevel(_octave_min, DATA_DOG);
00222         CuTexImage * got =  GetBaseLevel(_octave_min, DATA_GRAD);
00223         CuTexImage * key =  GetBaseLevel(_octave_min, DATA_KEYPOINT);
00224 
00226 
00227         for(i = 0; i< noct; i++)
00228         {
00229                 int wa = ((w + 3) / 4) * 4;
00230 
00231                 totalkb += ((nlev *8 -19)* (wa * h) * 4 / 1024);
00232                 for( j = 0; j< nlev; j++, gus++, dog++, got++, key++)
00233                 {
00234                         gus->InitTexture(wa, h); //nlev
00235                         if(j==0)continue;
00236                         dog->InitTexture(wa, h);  //nlev -1
00237                         if(     j >= 1 && j < 1 + param._dog_level_num)
00238                         {
00239                                 got->InitTexture(wa, h, 2); //2 * nlev - 6
00240                                 got->InitTexture2D();
00241                         }
00242                         if(j > 1 && j < nlev -1)        key->InitTexture(wa, h, 4); // nlev -3 ; 4 * nlev - 12
00243                 }
00244                 w>>=1;
00245                 h>>=1;
00246         }
00247 
00248         totalkb += ResizeFeatureStorage();
00249 
00250         if(ProgramCU::CheckErrorCUDA("ResizePyramid")) SetFailStatus(); 
00251 
00252         _allocated = 1;
00253 
00254         if(GlobalUtil::_verbose && GlobalUtil::_timingS) std::cout<<"[Allocate Pyramid]:\t" <<(totalkb/1024)<<"MB\n";
00255 
00256 }
00257 
00258 void PyramidCU::FitPyramid(int w, int h)
00259 {
00260         _pyramid_octave_first = 0;
00261         //
00262         _octave_num  = GlobalUtil::_octave_num_default;
00263 
00264         int _octave_num_max = max(1, (int) floor (log ( double(min(w, h)))/log(2.0))  -3 );
00265 
00266         if(_octave_num < 1 || _octave_num > _octave_num_max) 
00267         {
00268                 _octave_num = _octave_num_max;
00269         }
00270 
00271 
00272         int pw = _pyramid_width>>1, ph = _pyramid_height>>1;
00273         while(_pyramid_octave_first + _octave_num < _pyramid_octave_num &&  
00274                 pw >= w && ph >= h)
00275         {
00276                 _pyramid_octave_first++;
00277                 pw >>= 1;
00278                 ph >>= 1;
00279         }
00280 
00282         int nlev = param._level_num;
00283         CuTexImage * gus =  GetBaseLevel(_octave_min, DATA_GAUSSIAN);
00284         CuTexImage * dog =  GetBaseLevel(_octave_min, DATA_DOG);
00285         CuTexImage * got =  GetBaseLevel(_octave_min, DATA_GRAD);
00286         CuTexImage * key =  GetBaseLevel(_octave_min, DATA_KEYPOINT);
00287         for(int i = 0; i< _octave_num; i++)
00288         {
00289                 int wa = ((w + 3) / 4) * 4;
00290 
00291                 for(int j = 0; j< nlev; j++, gus++, dog++, got++, key++)
00292                 {
00293                         gus->InitTexture(wa, h); //nlev
00294                         if(j==0)continue;
00295                         dog->InitTexture(wa, h);  //nlev -1
00296                         if(     j >= 1 && j < 1 + param._dog_level_num)
00297                         {
00298                                 got->InitTexture(wa, h, 2); //2 * nlev - 6
00299                                 got->InitTexture2D();
00300                         }
00301                         if(j > 1 && j < nlev -1)        key->InitTexture(wa, h, 4); // nlev -3 ; 4 * nlev - 12
00302                 }
00303                 w>>=1;
00304                 h>>=1;
00305         }
00306 }
00307 
00308 int PyramidCU::CheckCudaDevice(int device)
00309 {
00310     return ProgramCU::CheckCudaDevice(device);
00311 }
00312 
00313 void PyramidCU::SetLevelFeatureNum(int idx, int fcount)
00314 {
00315         _featureTex[idx].InitTexture(fcount, 1, 4);
00316         _levelFeatureNum[idx] = fcount;
00317 }
00318 
00319 int PyramidCU::ResizeFeatureStorage()
00320 {
00321         int totalkb = 0;
00322         if(_levelFeatureNum==NULL)      _levelFeatureNum = new int[_octave_num * param._dog_level_num];
00323         std::fill(_levelFeatureNum, _levelFeatureNum+_octave_num * param._dog_level_num, 0); 
00324 
00325         int wmax = GetBaseLevel(_octave_min)->GetImgWidth();
00326         int hmax = GetBaseLevel(_octave_min)->GetImgHeight();
00327         int whmax = max(wmax, hmax);
00328         int w,  i;
00329 
00330         //
00331         int num = (int)ceil(log(double(whmax))/log(4.0));
00332 
00333         if( _hpLevelNum != num)
00334         {
00335                 _hpLevelNum = num;
00336                 if(_histoPyramidTex ) delete [] _histoPyramidTex;
00337                 _histoPyramidTex = new CuTexImage[_hpLevelNum];
00338         }
00339 
00340         for(i = 0, w = 1; i < _hpLevelNum; i++)
00341         {
00342                 _histoPyramidTex[i].InitTexture(w, whmax, 4);
00343                 w<<=2;
00344         }
00345 
00346         // (4 ^ (_hpLevelNum) -1 / 3) pixels
00347         totalkb += (((1 << (2 * _hpLevelNum)) -1) / 3 * 16 / 1024);
00348 
00349         //initialize the feature texture
00350         int idx = 0, n = _octave_num * param._dog_level_num;
00351         if(_featureTex==NULL)   _featureTex = new CuTexImage[n];
00352         if(GlobalUtil::_MaxOrientation >1 && GlobalUtil::_OrientationPack2==0 && _orientationTex== NULL)
00353                 _orientationTex = new CuTexImage[n];
00354 
00355 
00356         for(i = 0; i < _octave_num; i++)
00357         {
00358                 CuTexImage * tex = GetBaseLevel(i+_octave_min);
00359                 int fmax = int(tex->GetImgWidth() * tex->GetImgHeight()*GlobalUtil::_MaxFeaturePercent);
00360                 //
00361                 if(fmax > GlobalUtil::_MaxLevelFeatureNum) fmax = GlobalUtil::_MaxLevelFeatureNum;
00362                 else if(fmax < 32) fmax = 32;   //give it at least a space of 32 feature
00363 
00364                 for(int j = 0; j < param._dog_level_num; j++, idx++)
00365                 {
00366                         _featureTex[idx].InitTexture(fmax, 1, 4);
00367                         totalkb += fmax * 16 /1024;
00368                         //
00369                         if(GlobalUtil::_MaxOrientation>1 && GlobalUtil::_OrientationPack2 == 0)
00370                         {
00371                                 _orientationTex[idx].InitTexture(fmax, 1, 4);
00372                                 totalkb += fmax * 16 /1024;
00373                         }
00374                 }
00375         }
00376 
00377 
00378         //this just need be initialized once
00379         if(_descriptorTex==NULL)
00380         {
00381                 //initialize feature texture pyramid
00382                 int fmax = _featureTex->GetImgWidth();
00383                 _descriptorTex = new CuTexImage;
00384                 totalkb += ( fmax /2);
00385                 _descriptorTex->InitTexture(fmax *128, 1, 1);
00386         }else
00387         {
00388                 totalkb +=  _descriptorTex->GetDataSize()/1024;
00389         }
00390         return totalkb;
00391 }
00392 
00393 void PyramidCU::GetFeatureDescriptors() 
00394 {
00395         //descriptors...
00396         float* pd =  &_descriptor_buffer[0];
00397         vector<float> descriptor_buffer2;
00398 
00399         //use another buffer if we need to re-order the descriptors
00400         if(_keypoint_index.size() > 0)
00401         {
00402                 descriptor_buffer2.resize(_descriptor_buffer.size());
00403                 pd = &descriptor_buffer2[0];
00404         }
00405 
00406         CuTexImage * got, * ftex= _featureTex;
00407         for(int i = 0, idx = 0; i < _octave_num; i++)
00408         {
00409                 got = GetBaseLevel(i + _octave_min, DATA_GRAD) + 1;
00410                 for(int j = 0; j < param._dog_level_num; j++, ftex++, idx++, got++)
00411                 {
00412                         if(_levelFeatureNum[idx]==0) continue;
00413             ProgramCU::ComputeDescriptor(ftex, got, _descriptorTex, IsUsingRectDescription());//process
00414                         _descriptorTex->CopyToHost(pd); //readback descriptor
00415                         pd += 128*_levelFeatureNum[idx];
00416                 }
00417         }
00418 
00419         if(GlobalUtil::_timingS) ProgramCU::FinishCUDA();
00420 
00421         if(_keypoint_index.size() > 0)
00422         {
00423             //put the descriptor back to the original order for keypoint list.
00424                 for(int i = 0; i < _featureNum; ++i)
00425                 {
00426                         int index = _keypoint_index[i];
00427                         memcpy(&_descriptor_buffer[index*128], &descriptor_buffer2[i*128], 128 * sizeof(float));
00428                 }
00429         }
00430 
00431         if(ProgramCU::CheckErrorCUDA("PyramidCU::GetFeatureDescriptors")) SetFailStatus(); 
00432 }
00433 
00434 void PyramidCU::GenerateFeatureListTex() 
00435 {
00436 
00437         vector<float> list;
00438         int idx = 0;
00439         const double twopi = 2.0*3.14159265358979323846;
00440         float sigma_half_step = powf(2.0f, 0.5f / param._dog_level_num);
00441         float octave_sigma = _octave_min>=0? float(1<<_octave_min): 1.0f/(1<<(-_octave_min));
00442         float offset = GlobalUtil::_LoweOrigin? 0 : 0.5f; 
00443         if(_down_sample_factor>0) octave_sigma *= float(1<<_down_sample_factor); 
00444 
00445         _keypoint_index.resize(0); // should already be 0
00446         for(int i = 0; i < _octave_num; i++, octave_sigma*= 2.0f)
00447         {
00448                 for(int j = 0; j < param._dog_level_num; j++, idx++)
00449                 {
00450                         list.resize(0);
00451                         float level_sigma = param.GetLevelSigma(j + param._level_min + 1) * octave_sigma;
00452                         float sigma_min = level_sigma / sigma_half_step;
00453                         float sigma_max = level_sigma * sigma_half_step;
00454                         int fcount = 0 ;
00455                         for(int k = 0; k < _featureNum; k++)
00456                         {
00457                                 float * key = &_keypoint_buffer[k*4];
00458                 float sigmak = key[2]; 
00460                 if(IsUsingRectDescription()) sigmak = min(key[2], key[3]) / 12.0f; 
00461 
00462                                 if(   (sigmak >= sigma_min && sigmak < sigma_max)
00463                                         ||(sigmak < sigma_min && i ==0 && j == 0)
00464                                         ||(sigmak > sigma_max && i == _octave_num -1 && j == param._dog_level_num - 1))
00465                                 {
00466                                         //add this keypoint to the list
00467                                         list.push_back((key[0] - offset) / octave_sigma + 0.5f);
00468                                         list.push_back((key[1] - offset) / octave_sigma + 0.5f);
00469                     if(IsUsingRectDescription())
00470                     {
00471                         list.push_back(key[2] / octave_sigma);
00472                         list.push_back(key[3] / octave_sigma);
00473                     }else
00474                     {
00475                                             list.push_back(key[2] / octave_sigma);
00476                                             list.push_back((float)fmod(twopi-key[3], twopi));
00477                     }
00478                                         fcount ++;
00479                                         //save the index of keypoints
00480                                         _keypoint_index.push_back(k);
00481                                 }
00482 
00483                         }
00484 
00485                         _levelFeatureNum[idx] = fcount;
00486                         if(fcount==0)continue;
00487                         CuTexImage * ftex = _featureTex+idx;
00488 
00489                         SetLevelFeatureNum(idx, fcount);
00490                         ftex->CopyFromHost(&list[0]);
00491                 }
00492         }
00493 
00494         if(GlobalUtil::_verbose)
00495         {
00496                 std::cout<<"#Features:\t"<<_featureNum<<"\n";
00497         }
00498 
00499 }
00500 
00501 void PyramidCU::ReshapeFeatureListCPU() 
00502 {
00503         int i, szmax =0, sz;
00504         int n = param._dog_level_num*_octave_num;
00505         for( i = 0; i < n; i++) 
00506         {
00507                 sz = _levelFeatureNum[i];
00508                 if(sz > szmax ) szmax = sz;
00509         }
00510         float * buffer = new float[szmax*16];
00511         float * buffer1 = buffer;
00512         float * buffer2 = buffer + szmax*4;
00513 
00514 
00515 
00516         _featureNum = 0;
00517 
00518 #ifdef NO_DUPLICATE_DOWNLOAD
00519         const double twopi = 2.0*3.14159265358979323846;
00520         _keypoint_buffer.resize(0);
00521         float os = _octave_min>=0? float(1<<_octave_min): 1.0f/(1<<(-_octave_min));
00522         if(_down_sample_factor>0) os *= float(1<<_down_sample_factor); 
00523         float offset = GlobalUtil::_LoweOrigin? 0 : 0.5f;
00524 #endif
00525 
00526 
00527         for(i = 0; i < n; i++)
00528         {
00529                 if(_levelFeatureNum[i]==0)continue;
00530 
00531                 _featureTex[i].CopyToHost(buffer1);
00532                 
00533                 int fcount =0;
00534                 float * src = buffer1;
00535                 float * des = buffer2;
00536                 const static double factor  = 2.0*3.14159265358979323846/65535.0;
00537                 for(int j = 0; j < _levelFeatureNum[i]; j++, src+=4)
00538                 {
00539                         unsigned short * orientations = (unsigned short*) (&src[3]);
00540                         if(orientations[0] != 65535)
00541                         {
00542                                 des[0] = src[0];
00543                                 des[1] = src[1];
00544                                 des[2] = src[2];
00545                                 des[3] = float( factor* orientations[0]);
00546                                 fcount++;
00547                                 des += 4;
00548                                 if(orientations[1] != 65535 && orientations[1] != orientations[0])
00549                                 {
00550                                         des[0] = src[0];
00551                                         des[1] = src[1];
00552                                         des[2] = src[2];
00553                                         des[3] = float(factor* orientations[1]);        
00554                                         fcount++;
00555                                         des += 4;
00556                                 }
00557                         }
00558                 }
00559                 //texture size
00560                 SetLevelFeatureNum(i, fcount);
00561                 _featureTex[i].CopyFromHost(buffer2);
00562                 
00563                 if(fcount == 0) continue;
00564 
00565 #ifdef NO_DUPLICATE_DOWNLOAD
00566                 float oss = os * (1 << (i / param._dog_level_num));
00567                 _keypoint_buffer.resize((_featureNum + fcount) * 4);
00568                 float* ds = &_keypoint_buffer[_featureNum * 4];
00569                 float* fs = buffer2;
00570                 for(int k = 0;  k < fcount; k++, ds+=4, fs+=4)
00571                 {
00572                         ds[0] = oss*(fs[0]-0.5f) + offset;      //x
00573                         ds[1] = oss*(fs[1]-0.5f) + offset;      //y
00574                         ds[2] = oss*fs[2];  //scale
00575                         ds[3] = (float)fmod(twopi-fs[3], twopi);        //orientation, mirrored
00576                 }
00577 #endif
00578                 _featureNum += fcount;
00579         }
00580         delete[] buffer;
00581         if(GlobalUtil::_verbose)
00582         {
00583                 std::cout<<"#Features MO:\t"<<_featureNum<<endl;
00584         }
00585 }
00586 
00587 void PyramidCU::GenerateFeatureDisplayVBO() 
00588 {
00589         //it is weried that this part is very slow.
00590         //use a big VBO to save all the SIFT box vertices
00591         int nvbo = _octave_num * param._dog_level_num;
00592         if(_featureDisplayVBO==NULL)
00593         {
00594                 //initialize the vbos
00595                 _featureDisplayVBO = new GLuint[nvbo];
00596                 _featurePointVBO = new GLuint[nvbo];
00597                 glGenBuffers(nvbo, _featureDisplayVBO); 
00598                 glGenBuffers(nvbo, _featurePointVBO);
00599         }
00600         for(int i = 0; i < nvbo; i++)
00601         {
00602                 if(_levelFeatureNum[i]<=0)continue;
00603                 CuTexImage * ftex  = _featureTex + i;
00604                 CuTexImage texPBO1( _levelFeatureNum[i]* 10, 1, 4, _featureDisplayVBO[i]);
00605                 CuTexImage texPBO2(_levelFeatureNum[i], 1, 4, _featurePointVBO[i]);
00606                 ProgramCU::DisplayKeyBox(ftex, &texPBO1);
00607                 ProgramCU::DisplayKeyPoint(ftex, &texPBO2);     
00608         }
00609 }
00610 
00611 void PyramidCU::DestroySharedData() 
00612 {
00613         //histogram reduction
00614         if(_histoPyramidTex)
00615         {
00616                 delete[]        _histoPyramidTex;
00617                 _hpLevelNum = 0;
00618                 _histoPyramidTex = NULL;
00619         }
00620         //descriptor storage shared by all levels
00621         if(_descriptorTex)
00622         {
00623                 delete _descriptorTex;
00624                 _descriptorTex = NULL;
00625         }
00626         //cpu reduction buffer.
00627         if(_histo_buffer)
00628         {
00629                 delete[] _histo_buffer;
00630                 _histo_buffer = 0;
00631         }
00632 }
00633 
00634 void PyramidCU::DestroyPerLevelData() 
00635 {
00636         //integers vector to store the feature numbers.
00637         if(_levelFeatureNum)
00638         {
00639                 delete [] _levelFeatureNum;
00640                 _levelFeatureNum = NULL;
00641         }
00642         //texture used to store features
00643         if(     _featureTex)
00644         {
00645                 delete [] _featureTex;
00646                 _featureTex =   NULL;
00647         }
00648         //texture used for multi-orientation 
00649         if(_orientationTex)
00650         {
00651                 delete [] _orientationTex;
00652                 _orientationTex = NULL;
00653         }
00654         int no = _octave_num* param._dog_level_num;
00655 
00656         //two sets of vbos used to display the features
00657         if(_featureDisplayVBO)
00658         {
00659                 glDeleteBuffers(no, _featureDisplayVBO);
00660                 delete [] _featureDisplayVBO;
00661                 _featureDisplayVBO = NULL;
00662         }
00663         if( _featurePointVBO)
00664         {
00665                 glDeleteBuffers(no, _featurePointVBO);
00666                 delete [] _featurePointVBO;
00667                 _featurePointVBO = NULL;
00668         }
00669 }
00670 
00671 void PyramidCU::DestroyPyramidData()
00672 {
00673         if(_allPyramid)
00674         {
00675                 delete [] _allPyramid;
00676                 _allPyramid = NULL;
00677         }
00678 }
00679 
00680 void PyramidCU::DownloadKeypoints() 
00681 {
00682         const double twopi = 2.0*3.14159265358979323846;
00683         int idx = 0;
00684         float * buffer = &_keypoint_buffer[0];
00685         vector<float> keypoint_buffer2;
00686         //use a different keypoint buffer when processing with an exisint features list
00687         //without orientation information. 
00688         if(_keypoint_index.size() > 0)
00689         {
00690                 keypoint_buffer2.resize(_keypoint_buffer.size());
00691                 buffer = &keypoint_buffer2[0];
00692         }
00693         float * p = buffer, *ps;
00694         CuTexImage * ftex = _featureTex;
00696         float os = _octave_min>=0? float(1<<_octave_min): 1.0f/(1<<(-_octave_min));
00697         if(_down_sample_factor>0) os *= float(1<<_down_sample_factor); 
00698         float offset = GlobalUtil::_LoweOrigin? 0 : 0.5f;
00700         for(int i = 0; i < _octave_num; i++, os *= 2.0f)
00701         {
00702         
00703                 for(int j = 0; j  < param._dog_level_num; j++, idx++, ftex++)
00704                 {
00705 
00706                         if(_levelFeatureNum[idx]>0)
00707                         {       
00708                                 ftex->CopyToHost(ps = p);
00709                                 for(int k = 0;  k < _levelFeatureNum[idx]; k++, ps+=4)
00710                                 {
00711                                         ps[0] = os*(ps[0]-0.5f) + offset;       //x
00712                                         ps[1] = os*(ps[1]-0.5f) + offset;       //y
00713                                         ps[2] = os*ps[2]; 
00714                                         ps[3] = (float)fmod(twopi-ps[3], twopi);        //orientation, mirrored
00715                                 }
00716                                 p+= 4* _levelFeatureNum[idx];
00717                         }
00718                 }
00719         }
00720 
00721         //put the feature into their original order for existing keypoint 
00722         if(_keypoint_index.size() > 0)
00723         {
00724                 for(int i = 0; i < _featureNum; ++i)
00725                 {
00726                         int index = _keypoint_index[i];
00727                         memcpy(&_keypoint_buffer[index*4], &keypoint_buffer2[i*4], 4 * sizeof(float));
00728                 }
00729         }
00730 }
00731 
00732 void PyramidCU::GenerateFeatureListCPU()
00733 {
00734         //no cpu version provided
00735         GenerateFeatureList();
00736 }
00737 
00738 void PyramidCU::GenerateFeatureList(int i, int j, int reduction_count, vector<int>& hbuffer)
00739 {
00740     int fcount = 0, idx = i * param._dog_level_num  + j;
00741         int hist_level_num = _hpLevelNum - _pyramid_octave_first /2; 
00742         int ii, k, len; 
00743 
00744         CuTexImage * htex, * ftex, * tex, *got;
00745         ftex = _featureTex + idx;
00746         htex = _histoPyramidTex + hist_level_num -1;
00747         tex = GetBaseLevel(_octave_min + i, DATA_KEYPOINT) + 2 + j;
00748         got = GetBaseLevel(_octave_min + i, DATA_GRAD) + 2 + j;
00749 
00750         ProgramCU::InitHistogram(tex, htex);
00751 
00752         for(k = 0; k < reduction_count - 1; k++, htex--)
00753         {
00754                 ProgramCU::ReduceHistogram(htex, htex -1);      
00755         }
00756         
00757         //htex has the row reduction result
00758         len = htex->GetImgHeight() * 4;
00759         hbuffer.resize(len);
00760         ProgramCU::FinishCUDA();
00761         htex->CopyToHost(&hbuffer[0]);
00762         
00764         for(ii = 0; ii < len; ++ii)     {if(!(hbuffer[ii]>= 0)) hbuffer[ii] = 0; }//?
00765         
00766     
00767     for(ii = 0; ii < len; ++ii)         fcount += hbuffer[ii];
00768         SetLevelFeatureNum(idx, fcount);
00769         
00770     //build the feature list
00771         if(fcount > 0)
00772         {
00773                 _featureNum += fcount;
00774                 _keypoint_buffer.resize(fcount * 4);
00775                 //vector<int> ikbuf(fcount*4);
00776                 int* ibuf = (int*) (&_keypoint_buffer[0]);
00777 
00778                 for(ii = 0; ii < len; ++ii)
00779                 {
00780                         int x = ii%4, y = ii / 4;
00781                         for(int jj = 0 ; jj < hbuffer[ii]; ++jj, ibuf+=4)
00782                         {
00783                                 ibuf[0] = x; ibuf[1] = y; ibuf[2] = jj; ibuf[3] = 0;
00784                         }
00785                 }
00786                 _featureTex[idx].CopyFromHost(&_keypoint_buffer[0]);
00787         
00789                 ProgramCU::GenerateList(_featureTex + idx, ++htex);
00790                 for(k = 2; k < reduction_count; k++)
00791                 {
00792                         ProgramCU::GenerateList(_featureTex + idx, ++htex);
00793                 }
00794         }
00795 }
00796 
00797 void PyramidCU::GenerateFeatureList()
00798 {
00799         double t1, t2; 
00800         int ocount = 0, reduction_count;
00801     int reverse = (GlobalUtil::_TruncateMethod == 1);
00802 
00803         vector<int> hbuffer;
00804         _featureNum = 0;
00805 
00806         //for(int i = 0, idx = 0; i < _octave_num; i++)
00807     FOR_EACH_OCTAVE(i, reverse)
00808         {
00809         CuTexImage* tex = GetBaseLevel(_octave_min + i, DATA_KEYPOINT) + 2;
00810                 reduction_count = FitHistogramPyramid(tex);
00811 
00812                 if(GlobalUtil::_timingO)
00813                 {
00814                         t1 = CLOCK(); 
00815                         ocount = 0;
00816                         std::cout<<"#"<<i+_octave_min + _down_sample_factor<<":\t";
00817                 }
00818                 //for(int j = 0; j < param._dog_level_num; j++, idx++)
00819         FOR_EACH_LEVEL(j, reverse)
00820                 {
00821             if(GlobalUtil::_TruncateMethod && GlobalUtil::_FeatureCountThreshold > 0 && _featureNum > GlobalUtil::_FeatureCountThreshold) continue;
00822 
00823                 GenerateFeatureList(i, j, reduction_count, hbuffer);
00824 
00826                         if(GlobalUtil::_timingO)
00827                         {
00828                 int idx = i * param._dog_level_num + j;
00829                                 ocount += _levelFeatureNum[idx];
00830                                 std::cout<< _levelFeatureNum[idx] <<"\t";
00831                         }
00832                 }
00833                 if(GlobalUtil::_timingO)
00834                 {       
00835                         t2 = CLOCK(); 
00836                         std::cout << "| \t" << int(ocount) << " :\t(" << (t2 - t1) << ")\n";
00837                 }
00838         }
00840         CopyGradientTex();
00842         if(GlobalUtil::_timingS)ProgramCU::FinishCUDA();
00843 
00844         if(GlobalUtil::_verbose)
00845         {
00846                 std::cout<<"#Features:\t"<<_featureNum<<"\n";
00847         }
00848 
00849         if(ProgramCU::CheckErrorCUDA("PyramidCU::GenerateFeatureList")) SetFailStatus();
00850 }
00851 
00852 GLTexImage* PyramidCU::GetLevelTexture(int octave, int level)
00853 {
00854         return GetLevelTexture(octave, level, DATA_GAUSSIAN);
00855 }
00856 
00857 GLTexImage* PyramidCU::ConvertTexCU2GL(CuTexImage* tex, int dataName)
00858 {
00859         
00860         GLenum format = GL_LUMINANCE;
00861         int convert_done = 1;
00862     if(_bufferPBO == 0) glGenBuffers(1, &_bufferPBO);
00863     if(_bufferTEX == NULL) _bufferTEX = new GLTexImage;
00864         switch(dataName)
00865         {
00866         case DATA_GAUSSIAN:
00867                 {
00868                         convert_done = tex->CopyToPBO(_bufferPBO);
00869                         break;
00870                 }
00871         case DATA_DOG:
00872                 {
00873                         CuTexImage texPBO(tex->GetImgWidth(), tex->GetImgHeight(), 1, _bufferPBO);
00874                         if(texPBO._cuData == 0 || tex->_cuData == NULL) convert_done = 0;
00875                         else ProgramCU::DisplayConvertDOG(tex, &texPBO);
00876                         break;
00877                 }
00878         case DATA_GRAD:
00879                 {
00880                         CuTexImage texPBO(tex->GetImgWidth(), tex->GetImgHeight(), 1, _bufferPBO);
00881                         if(texPBO._cuData == 0 || tex->_cuData == NULL) convert_done = 0;
00882                         else ProgramCU::DisplayConvertGRD(tex, &texPBO);
00883                         break;
00884                 }
00885         case DATA_KEYPOINT:
00886                 {
00887                         CuTexImage * dog = tex - param._level_num * _pyramid_octave_num;
00888                         format = GL_RGBA;
00889                         CuTexImage texPBO(tex->GetImgWidth(), tex->GetImgHeight(), 4, _bufferPBO);
00890                         if(texPBO._cuData == 0 || tex->_cuData == NULL) convert_done = 0;
00891                         else ProgramCU::DisplayConvertKEY(tex, dog, &texPBO);
00892                         break;
00893                 }
00894         default:
00895                         convert_done = 0;
00896                         break;
00897         }
00898 
00899         if(convert_done)
00900         {
00901                 _bufferTEX->InitTexture(max(_bufferTEX->GetTexWidth(), tex->GetImgWidth()), max(_bufferTEX->GetTexHeight(), tex->GetImgHeight()));
00902                 _bufferTEX->CopyFromPBO(_bufferPBO, tex->GetImgWidth(), tex->GetImgHeight(), format);
00903         }else
00904         {
00905                 _bufferTEX->SetImageSize(0, 0);
00906         }
00907 
00908         return _bufferTEX;
00909 }
00910 
00911 GLTexImage* PyramidCU::GetLevelTexture(int octave, int level, int dataName) 
00912 {
00913         CuTexImage* tex = GetBaseLevel(octave, dataName) + (level - param._level_min);
00914         //CuTexImage* gus = GetBaseLevel(octave, DATA_GAUSSIAN) + (level - param._level_min); 
00915         return ConvertTexCU2GL(tex, dataName);
00916 }
00917 
00918 void PyramidCU::ConvertInputToCU(GLTexInput* input)
00919 {
00920         int ws = input->GetImgWidth(), hs = input->GetImgHeight();
00921         TruncateWidth(ws);
00922         //copy the input image to pixel buffer object
00923     if(input->_pixel_data)
00924     {
00925         _inputTex->InitTexture(ws, hs, 1);
00926         _inputTex->CopyFromHost(input->_pixel_data); 
00927     }else
00928     {
00929         if(_bufferPBO == 0) glGenBuffers(1, &_bufferPBO);
00930         if(input->_rgb_converted && input->CopyToPBO(_bufferPBO, ws, hs, GL_LUMINANCE))
00931         {
00932                     _inputTex->InitTexture(ws, hs, 1);
00933             _inputTex->CopyFromPBO(ws, hs, _bufferPBO); 
00934         }else if(input->CopyToPBO(_bufferPBO, ws, hs))
00935             {
00936                     CuTexImage texPBO(ws, hs, 4, _bufferPBO);
00937                     _inputTex->InitTexture(ws, hs, 1);
00938                     ProgramCU::ReduceToSingleChannel(_inputTex, &texPBO, !input->_rgb_converted);
00939             }else
00940             {
00941                     std::cerr<< "Unable To Convert Intput\n";
00942             }
00943     }
00944 }
00945 
00946 void PyramidCU::BuildPyramid(GLTexInput * input)
00947 {
00948 
00949         USE_TIMING();
00950 
00951         int i, j;
00952         
00953         for ( i = _octave_min; i < _octave_min + _octave_num; i++)
00954         {
00955 
00956                 float* filter_sigma = param._sigma;
00957                 CuTexImage *tex = GetBaseLevel(i);
00958                 CuTexImage *buf = GetBaseLevel(i, DATA_KEYPOINT) +2;
00959                 j = param._level_min + 1;
00960 
00961                 OCTAVE_START();
00962 
00963                 if( i == _octave_min )
00964                 {       
00965                         ConvertInputToCU(input);
00966 
00967                         if(i == 0)
00968                         {
00969                                 ProgramCU::FilterImage(tex, _inputTex, buf, 
00970                     param.GetInitialSmoothSigma(_octave_min + _down_sample_factor));
00971                         }else
00972                         {
00973                                 if(i < 0)       ProgramCU::SampleImageU(tex, _inputTex, -i);                    
00974                                 else            ProgramCU::SampleImageD(tex, _inputTex, i);
00975                                 ProgramCU::FilterImage(tex, tex, buf, 
00976                     param.GetInitialSmoothSigma(_octave_min + _down_sample_factor));
00977                         }
00978                 }else
00979                 {
00980                         ProgramCU::SampleImageD(tex, GetBaseLevel(i - 1) + param._level_ds - param._level_min); 
00981                         if(param._sigma_skip1 > 0)
00982                         {
00983                                 ProgramCU::FilterImage(tex, tex, buf, param._sigma_skip1);
00984                         }
00985                 }
00986                 LEVEL_FINISH();
00987                 for( ; j <=  param._level_max ; j++, tex++, filter_sigma++)
00988                 {
00989                         // filtering
00990                         ProgramCU::FilterImage(tex + 1, tex, buf, *filter_sigma);
00991                         LEVEL_FINISH();
00992                 }
00993                 OCTAVE_FINISH();
00994         }
00995         if(GlobalUtil::_timingS) ProgramCU::FinishCUDA();
00996 
00997         if(ProgramCU::CheckErrorCUDA("PyramidCU::BuildPyramid")) SetFailStatus();
00998 }
00999 
01000 void PyramidCU::DetectKeypointsEX()
01001 {
01002 
01003 
01004         int i, j;
01005         double t0, t, ts, t1, t2;
01006 
01007         if(GlobalUtil::_timingS && GlobalUtil::_verbose)ts = CLOCK();
01008 
01009         for(i = _octave_min; i < _octave_min + _octave_num; i++)
01010         {
01011                 CuTexImage * gus = GetBaseLevel(i) + 1;
01012                 CuTexImage * dog = GetBaseLevel(i, DATA_DOG) + 1;
01013                 CuTexImage * got = GetBaseLevel(i, DATA_GRAD) + 1;
01014                 //compute the gradient
01015                 for(j = param._level_min +1; j <=  param._level_max ; j++, gus++, dog++, got++)
01016                 {
01017                         //input: gus and gus -1
01018                         //output: gradient, dog, orientation
01019                         ProgramCU::ComputeDOG(gus, dog, got);
01020                 }
01021         }
01022         if(GlobalUtil::_timingS && GlobalUtil::_verbose)
01023         {
01024                 ProgramCU::FinishCUDA();
01025                 t1 = CLOCK();
01026         }
01027 
01028         for ( i = _octave_min; i < _octave_min + _octave_num; i++)
01029         {
01030                 if(GlobalUtil::_timingO)
01031                 {
01032                         t0 = CLOCK();
01033                         std::cout<<"#"<<(i + _down_sample_factor)<<"\t";
01034                 }
01035                 CuTexImage * dog = GetBaseLevel(i, DATA_DOG) + 2;
01036                 CuTexImage * key = GetBaseLevel(i, DATA_KEYPOINT) +2;
01037 
01038 
01039                 for( j = param._level_min +2; j <  param._level_max ; j++, dog++, key++)
01040                 {
01041                         if(GlobalUtil::_timingL)t = CLOCK();
01042                         //input, dog, dog + 1, dog -1
01043                         //output, key
01044                         ProgramCU::ComputeKEY(dog, key, param._dog_threshold, param._edge_threshold);
01045                         if(GlobalUtil::_timingL)
01046                         {
01047                                 std::cout<<(CLOCK()-t)<<"\t";
01048                         }
01049                 }
01050                 if(GlobalUtil::_timingO)
01051                 {
01052                         std::cout<<"|\t"<<(CLOCK()-t0)<<"\n";
01053                 }
01054         }
01055 
01056         if(GlobalUtil::_timingS)
01057         {
01058                 ProgramCU::FinishCUDA();
01059                 if(GlobalUtil::_verbose) 
01060                 {       
01061                         t2 = CLOCK();
01062                         std::cout       <<"<Gradient, DOG  >\t"<<(t1-ts)<<"\n"
01063                                                 <<"<Get Keypoints  >\t"<<(t2-t1)<<"\n";
01064                 }                               
01065         }
01066 }
01067 
01068 void PyramidCU::CopyGradientTex()
01069 {
01070         double ts, t1;
01071 
01072         if(GlobalUtil::_timingS && GlobalUtil::_verbose)ts = CLOCK();
01073 
01074         for(int i = 0, idx = 0; i < _octave_num; i++)
01075         {
01076                 CuTexImage * got = GetBaseLevel(i + _octave_min, DATA_GRAD) +  1;
01077                 //compute the gradient
01078                 for(int j = 0; j <  param._dog_level_num ; j++, got++, idx++)
01079                 {
01080                         if(_levelFeatureNum[idx] > 0)   got->CopyToTexture2D();
01081                 }
01082         }
01083         if(GlobalUtil::_timingS)
01084         {
01085                 ProgramCU::FinishCUDA();
01086                 if(GlobalUtil::_verbose)
01087                 {
01088                         t1 = CLOCK();
01089                         std::cout       <<"<Copy Grad/Orientation>\t"<<(t1-ts)<<"\n";
01090                 }
01091         }
01092 }
01093 
01094 void PyramidCU::ComputeGradient() 
01095 {
01096 
01097         int i, j;
01098         double ts, t1;
01099 
01100         if(GlobalUtil::_timingS && GlobalUtil::_verbose)ts = CLOCK();
01101 
01102         for(i = _octave_min; i < _octave_min + _octave_num; i++)
01103         {
01104                 CuTexImage * gus = GetBaseLevel(i) +  1;
01105                 CuTexImage * dog = GetBaseLevel(i, DATA_DOG) +  1;
01106                 CuTexImage * got = GetBaseLevel(i, DATA_GRAD) +  1;
01107 
01108                 //compute the gradient
01109                 for(j = 0; j <  param._dog_level_num ; j++, gus++, dog++, got++)
01110                 {
01111                         ProgramCU::ComputeDOG(gus, dog, got);
01112                 }
01113         }
01114         if(GlobalUtil::_timingS)
01115         {
01116                 ProgramCU::FinishCUDA();
01117                 if(GlobalUtil::_verbose)
01118                 {
01119                         t1 = CLOCK();
01120                         std::cout       <<"<Gradient, DOG  >\t"<<(t1-ts)<<"\n";
01121                 }
01122         }
01123 }
01124 
01125 int PyramidCU::FitHistogramPyramid(CuTexImage* tex)
01126 {
01127         CuTexImage *htex;
01128         int hist_level_num = _hpLevelNum - _pyramid_octave_first / 2; 
01129         htex = _histoPyramidTex + hist_level_num - 1;
01130         int w = (tex->GetImgWidth() + 2) >> 2;
01131         int h = tex->GetImgHeight();
01132         int count = 0; 
01133         for(int k = 0; k < hist_level_num; k++, htex--)
01134         {
01135                 //htex->SetImageSize(w, h);     
01136                 htex->InitTexture(w, h, 4); 
01137                 ++count;
01138                 if(w == 1)
01139             break;
01140                 w = (w + 3)>>2; 
01141         }
01142         return count;
01143 }
01144 
01145 void PyramidCU::GetFeatureOrientations() 
01146 {
01147 
01148         CuTexImage * ftex = _featureTex;
01149         int * count      = _levelFeatureNum;
01150         float sigma, sigma_step = powf(2.0f, 1.0f/param._dog_level_num);
01151 
01152         for(int i = 0; i < _octave_num; i++)
01153         {
01154                 CuTexImage* got = GetBaseLevel(i + _octave_min, DATA_GRAD) + 1;
01155                 CuTexImage* key = GetBaseLevel(i + _octave_min, DATA_KEYPOINT) + 2;
01156 
01157                 for(int j = 0; j < param._dog_level_num; j++, ftex++, count++, got++, key++)
01158                 {
01159                         if(*count<=0)continue;
01160 
01161                         //if(ftex->GetImgWidth() < *count) ftex->InitTexture(*count, 1, 4);
01162 
01163                         sigma = param.GetLevelSigma(j+param._level_min+1);
01164 
01165                         ProgramCU::ComputeOrientation(ftex, got, key, sigma, sigma_step, _existing_keypoints);          
01166                 }
01167         }
01168 
01169         if(GlobalUtil::_timingS)ProgramCU::FinishCUDA();
01170         if(ProgramCU::CheckErrorCUDA("PyramidCU::GetFeatureOrientations")) SetFailStatus();
01171 
01172 }
01173 
01174 void PyramidCU::GetSimplifiedOrientation() 
01175 {
01176         //no simplified orientation
01177         GetFeatureOrientations();
01178 }
01179 
01180 CuTexImage* PyramidCU::GetBaseLevel(int octave, int dataName)
01181 {
01182         if(octave <_octave_min || octave > _octave_min + _octave_num) return NULL;
01183         int offset = (_pyramid_octave_first + octave - _octave_min) * param._level_num;
01184         int num = param._level_num * _pyramid_octave_num;
01185         if (dataName == DATA_ROT) dataName = DATA_GRAD;
01186         return _allPyramid + num * dataName + offset;
01187 }
01188 
01189 #endif
01190 


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