00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00045
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
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
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 if(toobig && GlobalUtil::_verbose && _octave_min > 0)
00132 {
00133 std::cout<< "**************************************************************\n"
00134 "Image larger than allowed dimension, data will be downsampled!\n"
00135 "use -maxd to change the settings\n"
00136 "***************************************************************\n";
00137 }
00138
00139 if( wp == _pyramid_width && hp == _pyramid_height && _allocated )
00140 {
00141 FitPyramid(wp, hp);
00142 }else if(GlobalUtil::_ForceTightPyramid || _allocated ==0)
00143 {
00144 ResizePyramid(wp, hp);
00145 }
00146 else if( wp > _pyramid_width || hp > _pyramid_height )
00147 {
00148 ResizePyramid(max(wp, _pyramid_width), max(hp, _pyramid_height));
00149 if(wp < _pyramid_width || hp < _pyramid_height) FitPyramid(wp, hp);
00150 }
00151 else
00152 {
00153
00154 FitPyramid(wp, hp);
00155 }
00156 }
00157
00158 void PyramidCU::ResizePyramid(int w, int h)
00159 {
00160
00161 unsigned int totalkb = 0;
00162 int _octave_num_new, input_sz, i, j;
00163
00164
00165 if(_pyramid_width == w && _pyramid_height == h && _allocated) return;
00166
00167 if(w > GlobalUtil::_texMaxDim || h > GlobalUtil::_texMaxDim) return ;
00168
00169 if(GlobalUtil::_verbose && GlobalUtil::_timingS) std::cout<<"[Allocate Pyramid]:\t" <<w<<"x"<<h<<endl;
00170
00171 _pyramid_octave_first = 0;
00172
00173
00174
00175
00176 input_sz = min(w,h) ;
00177 _pyramid_width = w;
00178 _pyramid_height = h;
00179
00180
00181
00182
00183
00184 _octave_num_new = GlobalUtil::_octave_num_default;
00185
00186 if(_octave_num_new < 1)
00187 {
00188 _octave_num_new = (int) floor (log ( double(input_sz))/log(2.0)) -3 ;
00189 if(_octave_num_new<1 ) _octave_num_new = 1;
00190 }
00191
00192 if(_pyramid_octave_num != _octave_num_new)
00193 {
00194
00195 if(_octave_num >0)
00196 {
00197 DestroyPerLevelData();
00198 DestroyPyramidData();
00199 }
00200 _pyramid_octave_num = _octave_num_new;
00201 }
00202
00203 _octave_num = _pyramid_octave_num;
00204
00205 int noct = _octave_num;
00206 int nlev = param._level_num;
00207
00208
00209 if(_allPyramid==NULL) _allPyramid = new CuTexImage[ noct* nlev * DATA_NUM];
00210
00211 CuTexImage * gus = GetBaseLevel(_octave_min, DATA_GAUSSIAN);
00212 CuTexImage * dog = GetBaseLevel(_octave_min, DATA_DOG);
00213 CuTexImage * got = GetBaseLevel(_octave_min, DATA_GRAD);
00214 CuTexImage * key = GetBaseLevel(_octave_min, DATA_KEYPOINT);
00215
00217
00218 for(i = 0; i< noct; i++)
00219 {
00220 int wa = ((w + 3) / 4) * 4;
00221
00222 totalkb += ((nlev *8 -19)* (wa * h) * 4 / 1024);
00223 for( j = 0; j< nlev; j++, gus++, dog++, got++, key++)
00224 {
00225 gus->InitTexture(wa, h);
00226 if(j==0)continue;
00227 dog->InitTexture(wa, h);
00228 if( j >= 1 && j < 1 + param._dog_level_num)
00229 {
00230 got->InitTexture(wa, h, 2);
00231 got->InitTexture2D();
00232 }
00233 if(j > 1 && j < nlev -1) key->InitTexture(wa, h, 4);
00234 }
00235 w>>=1;
00236 h>>=1;
00237 }
00238
00239 totalkb += ResizeFeatureStorage();
00240
00241 if(ProgramCU::CheckErrorCUDA("ResizePyramid")) SetFailStatus();
00242
00243 _allocated = 1;
00244
00245 if(GlobalUtil::_verbose && GlobalUtil::_timingS) std::cout<<"[Allocate Pyramid]:\t" <<(totalkb/1024)<<"MB\n";
00246
00247 }
00248
00249 void PyramidCU::FitPyramid(int w, int h)
00250 {
00251 _pyramid_octave_first = 0;
00252
00253 _octave_num = GlobalUtil::_octave_num_default;
00254
00255 int _octave_num_max = max(1, (int) floor (log ( double(min(w, h)))/log(2.0)) -3 );
00256
00257 if(_octave_num < 1 || _octave_num > _octave_num_max)
00258 {
00259 _octave_num = _octave_num_max;
00260 }
00261
00262
00263 int pw = _pyramid_width>>1, ph = _pyramid_height>>1;
00264 while(_pyramid_octave_first + _octave_num < _pyramid_octave_num &&
00265 pw >= w && ph >= h)
00266 {
00267 _pyramid_octave_first++;
00268 pw >>= 1;
00269 ph >>= 1;
00270 }
00271
00273 int nlev = param._level_num;
00274 CuTexImage * gus = GetBaseLevel(_octave_min, DATA_GAUSSIAN);
00275 CuTexImage * dog = GetBaseLevel(_octave_min, DATA_DOG);
00276 CuTexImage * got = GetBaseLevel(_octave_min, DATA_GRAD);
00277 CuTexImage * key = GetBaseLevel(_octave_min, DATA_KEYPOINT);
00278 for(int i = 0; i< _octave_num; i++)
00279 {
00280 int wa = ((w + 3) / 4) * 4;
00281
00282 for(int j = 0; j< nlev; j++, gus++, dog++, got++, key++)
00283 {
00284 gus->InitTexture(wa, h);
00285 if(j==0)continue;
00286 dog->InitTexture(wa, h);
00287 if( j >= 1 && j < 1 + param._dog_level_num)
00288 {
00289 got->InitTexture(wa, h, 2);
00290 got->InitTexture2D();
00291 }
00292 if(j > 1 && j < nlev -1) key->InitTexture(wa, h, 4);
00293 }
00294 w>>=1;
00295 h>>=1;
00296 }
00297 }
00298
00299 int PyramidCU::CheckCudaDevice(int device)
00300 {
00301 return ProgramCU::CheckCudaDevice(device);
00302 }
00303
00304 void PyramidCU::SetLevelFeatureNum(int idx, int fcount)
00305 {
00306 _featureTex[idx].InitTexture(fcount, 1, 4);
00307 _levelFeatureNum[idx] = fcount;
00308 }
00309
00310 int PyramidCU::ResizeFeatureStorage()
00311 {
00312 int totalkb = 0;
00313 if(_levelFeatureNum==NULL) _levelFeatureNum = new int[_octave_num * param._dog_level_num];
00314 std::fill(_levelFeatureNum, _levelFeatureNum+_octave_num * param._dog_level_num, 0);
00315
00316 int wmax = GetBaseLevel(_octave_min)->GetImgWidth();
00317 int hmax = GetBaseLevel(_octave_min)->GetImgHeight();
00318 int whmax = max(wmax, hmax);
00319 int w, i;
00320
00321
00322 int num = (int)ceil(log(double(whmax))/log(4.0));
00323
00324 if( _hpLevelNum != num)
00325 {
00326 _hpLevelNum = num;
00327 if(_histoPyramidTex ) delete [] _histoPyramidTex;
00328 _histoPyramidTex = new CuTexImage[_hpLevelNum];
00329 }
00330
00331 for(i = 0, w = 1; i < _hpLevelNum; i++)
00332 {
00333 _histoPyramidTex[i].InitTexture(w, whmax, 4);
00334 w<<=2;
00335 }
00336
00337
00338 totalkb += (((1 << (2 * _hpLevelNum)) -1) / 3 * 16 / 1024);
00339
00340
00341 int idx = 0, n = _octave_num * param._dog_level_num;
00342 if(_featureTex==NULL) _featureTex = new CuTexImage[n];
00343 if(GlobalUtil::_MaxOrientation >1 && GlobalUtil::_OrientationPack2==0 && _orientationTex== NULL)
00344 _orientationTex = new CuTexImage[n];
00345
00346
00347 for(i = 0; i < _octave_num; i++)
00348 {
00349 CuTexImage * tex = GetBaseLevel(i+_octave_min);
00350 int fmax = int(tex->GetImgWidth() * tex->GetImgHeight()*GlobalUtil::_MaxFeaturePercent);
00351
00352 if(fmax > GlobalUtil::_MaxLevelFeatureNum) fmax = GlobalUtil::_MaxLevelFeatureNum;
00353 else if(fmax < 32) fmax = 32;
00354
00355 for(int j = 0; j < param._dog_level_num; j++, idx++)
00356 {
00357 _featureTex[idx].InitTexture(fmax, 1, 4);
00358 totalkb += fmax * 16 /1024;
00359
00360 if(GlobalUtil::_MaxOrientation>1 && GlobalUtil::_OrientationPack2 == 0)
00361 {
00362 _orientationTex[idx].InitTexture(fmax, 1, 4);
00363 totalkb += fmax * 16 /1024;
00364 }
00365 }
00366 }
00367
00368
00369
00370 if(_descriptorTex==NULL)
00371 {
00372
00373 int fmax = _featureTex->GetImgWidth();
00374 _descriptorTex = new CuTexImage;
00375 totalkb += ( fmax /2);
00376 _descriptorTex->InitTexture(fmax *128, 1, 1);
00377 }else
00378 {
00379 totalkb += _descriptorTex->GetDataSize()/1024;
00380 }
00381 return totalkb;
00382 }
00383
00384 void PyramidCU::GetFeatureDescriptors()
00385 {
00386
00387 float* pd = &_descriptor_buffer[0];
00388 vector<float> descriptor_buffer2;
00389
00390
00391 if(_keypoint_index.size() > 0)
00392 {
00393 descriptor_buffer2.resize(_descriptor_buffer.size());
00394 pd = &descriptor_buffer2[0];
00395 }
00396
00397 CuTexImage * got, * ftex= _featureTex;
00398 for(int i = 0, idx = 0; i < _octave_num; i++)
00399 {
00400 got = GetBaseLevel(i + _octave_min, DATA_GRAD) + 1;
00401 for(int j = 0; j < param._dog_level_num; j++, ftex++, idx++, got++)
00402 {
00403 if(_levelFeatureNum[idx]==0) continue;
00404 ProgramCU::ComputeDescriptor(ftex, got, _descriptorTex, IsUsingRectDescription());
00405 _descriptorTex->CopyToHost(pd);
00406 pd += 128*_levelFeatureNum[idx];
00407 }
00408 }
00409
00410 if(GlobalUtil::_timingS) ProgramCU::FinishCUDA();
00411
00412 if(_keypoint_index.size() > 0)
00413 {
00414
00415 for(int i = 0; i < _featureNum; ++i)
00416 {
00417 int index = _keypoint_index[i];
00418 memcpy(&_descriptor_buffer[index*128], &descriptor_buffer2[i*128], 128 * sizeof(float));
00419 }
00420 }
00421
00422 if(ProgramCU::CheckErrorCUDA("PyramidCU::GetFeatureDescriptors")) SetFailStatus();
00423 }
00424
00425 void PyramidCU::GenerateFeatureListTex()
00426 {
00427
00428 vector<float> list;
00429 int idx = 0;
00430 const double twopi = 2.0*3.14159265358979323846;
00431 float sigma_half_step = powf(2.0f, 0.5f / param._dog_level_num);
00432 float octave_sigma = _octave_min>=0? float(1<<_octave_min): 1.0f/(1<<(-_octave_min));
00433 float offset = GlobalUtil::_LoweOrigin? 0 : 0.5f;
00434 if(_down_sample_factor>0) octave_sigma *= float(1<<_down_sample_factor);
00435
00436 _keypoint_index.resize(0);
00437 for(int i = 0; i < _octave_num; i++, octave_sigma*= 2.0f)
00438 {
00439 for(int j = 0; j < param._dog_level_num; j++, idx++)
00440 {
00441 list.resize(0);
00442 float level_sigma = param.GetLevelSigma(j + param._level_min + 1) * octave_sigma;
00443 float sigma_min = level_sigma / sigma_half_step;
00444 float sigma_max = level_sigma * sigma_half_step;
00445 int fcount = 0 ;
00446 for(int k = 0; k < _featureNum; k++)
00447 {
00448 float * key = &_keypoint_buffer[k*4];
00449 float sigmak = key[2];
00451 if(IsUsingRectDescription()) sigmak = min(key[2], key[3]) / 12.0f;
00452
00453 if( (sigmak >= sigma_min && sigmak < sigma_max)
00454 ||(sigmak < sigma_min && i ==0 && j == 0)
00455 ||(sigmak > sigma_max && i == _octave_num -1 && j == param._dog_level_num - 1))
00456 {
00457
00458 list.push_back((key[0] - offset) / octave_sigma + 0.5f);
00459 list.push_back((key[1] - offset) / octave_sigma + 0.5f);
00460 if(IsUsingRectDescription())
00461 {
00462 list.push_back(key[2] / octave_sigma);
00463 list.push_back(key[3] / octave_sigma);
00464 }else
00465 {
00466 list.push_back(key[2] / octave_sigma);
00467 list.push_back((float)fmod(twopi-key[3], twopi));
00468 }
00469 fcount ++;
00470
00471 _keypoint_index.push_back(k);
00472 }
00473
00474 }
00475
00476 _levelFeatureNum[idx] = fcount;
00477 if(fcount==0)continue;
00478 CuTexImage * ftex = _featureTex+idx;
00479
00480 SetLevelFeatureNum(idx, fcount);
00481 ftex->CopyFromHost(&list[0]);
00482 }
00483 }
00484
00485 if(GlobalUtil::_verbose)
00486 {
00487 std::cout<<"#Features:\t"<<_featureNum<<"\n";
00488 }
00489
00490 }
00491
00492 void PyramidCU::ReshapeFeatureListCPU()
00493 {
00494 int i, szmax =0, sz;
00495 int n = param._dog_level_num*_octave_num;
00496 for( i = 0; i < n; i++)
00497 {
00498 sz = _levelFeatureNum[i];
00499 if(sz > szmax ) szmax = sz;
00500 }
00501 float * buffer = new float[szmax*16];
00502 float * buffer1 = buffer;
00503 float * buffer2 = buffer + szmax*4;
00504
00505
00506
00507 _featureNum = 0;
00508
00509 #ifdef NO_DUPLICATE_DOWNLOAD
00510 const double twopi = 2.0*3.14159265358979323846;
00511 _keypoint_buffer.resize(0);
00512 float os = _octave_min>=0? float(1<<_octave_min): 1.0f/(1<<(-_octave_min));
00513 if(_down_sample_factor>0) os *= float(1<<_down_sample_factor);
00514 float offset = GlobalUtil::_LoweOrigin? 0 : 0.5f;
00515 #endif
00516
00517
00518 for(i = 0; i < n; i++)
00519 {
00520 if(_levelFeatureNum[i]==0)continue;
00521
00522 _featureTex[i].CopyToHost(buffer1);
00523
00524 int fcount =0;
00525 float * src = buffer1;
00526 float * des = buffer2;
00527 const static double factor = 2.0*3.14159265358979323846/65535.0;
00528 for(int j = 0; j < _levelFeatureNum[i]; j++, src+=4)
00529 {
00530 unsigned short * orientations = (unsigned short*) (&src[3]);
00531 if(orientations[0] != 65535)
00532 {
00533 des[0] = src[0];
00534 des[1] = src[1];
00535 des[2] = src[2];
00536 des[3] = float( factor* orientations[0]);
00537 fcount++;
00538 des += 4;
00539 if(orientations[1] != 65535 && orientations[1] != orientations[0])
00540 {
00541 des[0] = src[0];
00542 des[1] = src[1];
00543 des[2] = src[2];
00544 des[3] = float(factor* orientations[1]);
00545 fcount++;
00546 des += 4;
00547 }
00548 }
00549 }
00550
00551 SetLevelFeatureNum(i, fcount);
00552 _featureTex[i].CopyFromHost(buffer2);
00553
00554 if(fcount == 0) continue;
00555
00556 #ifdef NO_DUPLICATE_DOWNLOAD
00557 float oss = os * (1 << (i / param._dog_level_num));
00558 _keypoint_buffer.resize((_featureNum + fcount) * 4);
00559 float* ds = &_keypoint_buffer[_featureNum * 4];
00560 float* fs = buffer2;
00561 for(int k = 0; k < fcount; k++, ds+=4, fs+=4)
00562 {
00563 ds[0] = oss*(fs[0]-0.5f) + offset;
00564 ds[1] = oss*(fs[1]-0.5f) + offset;
00565 ds[2] = oss*fs[2];
00566 ds[3] = (float)fmod(twopi-fs[3], twopi);
00567 }
00568 #endif
00569 _featureNum += fcount;
00570 }
00571 delete[] buffer;
00572 if(GlobalUtil::_verbose)
00573 {
00574 std::cout<<"#Features MO:\t"<<_featureNum<<endl;
00575 }
00576 }
00577
00578 void PyramidCU::GenerateFeatureDisplayVBO()
00579 {
00580
00581
00582 int nvbo = _octave_num * param._dog_level_num;
00583 if(_featureDisplayVBO==NULL)
00584 {
00585
00586 _featureDisplayVBO = new GLuint[nvbo];
00587 _featurePointVBO = new GLuint[nvbo];
00588 glGenBuffers(nvbo, _featureDisplayVBO);
00589 glGenBuffers(nvbo, _featurePointVBO);
00590 }
00591 for(int i = 0; i < nvbo; i++)
00592 {
00593 if(_levelFeatureNum[i]<=0)continue;
00594 CuTexImage * ftex = _featureTex + i;
00595 CuTexImage texPBO1( _levelFeatureNum[i]* 10, 1, 4, _featureDisplayVBO[i]);
00596 CuTexImage texPBO2(_levelFeatureNum[i], 1, 4, _featurePointVBO[i]);
00597 ProgramCU::DisplayKeyBox(ftex, &texPBO1);
00598 ProgramCU::DisplayKeyPoint(ftex, &texPBO2);
00599 }
00600 }
00601
00602 void PyramidCU::DestroySharedData()
00603 {
00604
00605 if(_histoPyramidTex)
00606 {
00607 delete[] _histoPyramidTex;
00608 _hpLevelNum = 0;
00609 _histoPyramidTex = NULL;
00610 }
00611
00612 if(_descriptorTex)
00613 {
00614 delete _descriptorTex;
00615 _descriptorTex = NULL;
00616 }
00617
00618 if(_histo_buffer)
00619 {
00620 delete[] _histo_buffer;
00621 _histo_buffer = 0;
00622 }
00623 }
00624
00625 void PyramidCU::DestroyPerLevelData()
00626 {
00627
00628 if(_levelFeatureNum)
00629 {
00630 delete [] _levelFeatureNum;
00631 _levelFeatureNum = NULL;
00632 }
00633
00634 if( _featureTex)
00635 {
00636 delete [] _featureTex;
00637 _featureTex = NULL;
00638 }
00639
00640 if(_orientationTex)
00641 {
00642 delete [] _orientationTex;
00643 _orientationTex = NULL;
00644 }
00645 int no = _octave_num* param._dog_level_num;
00646
00647
00648 if(_featureDisplayVBO)
00649 {
00650 glDeleteBuffers(no, _featureDisplayVBO);
00651 delete [] _featureDisplayVBO;
00652 _featureDisplayVBO = NULL;
00653 }
00654 if( _featurePointVBO)
00655 {
00656 glDeleteBuffers(no, _featurePointVBO);
00657 delete [] _featurePointVBO;
00658 _featurePointVBO = NULL;
00659 }
00660 }
00661
00662 void PyramidCU::DestroyPyramidData()
00663 {
00664 if(_allPyramid)
00665 {
00666 delete [] _allPyramid;
00667 _allPyramid = NULL;
00668 }
00669 }
00670
00671 void PyramidCU::DownloadKeypoints()
00672 {
00673 const double twopi = 2.0*3.14159265358979323846;
00674 int idx = 0;
00675 float * buffer = &_keypoint_buffer[0];
00676 vector<float> keypoint_buffer2;
00677
00678
00679 if(_keypoint_index.size() > 0)
00680 {
00681 keypoint_buffer2.resize(_keypoint_buffer.size());
00682 buffer = &keypoint_buffer2[0];
00683 }
00684 float * p = buffer, *ps;
00685 CuTexImage * ftex = _featureTex;
00687 float os = _octave_min>=0? float(1<<_octave_min): 1.0f/(1<<(-_octave_min));
00688 if(_down_sample_factor>0) os *= float(1<<_down_sample_factor);
00689 float offset = GlobalUtil::_LoweOrigin? 0 : 0.5f;
00691 for(int i = 0; i < _octave_num; i++, os *= 2.0f)
00692 {
00693
00694 for(int j = 0; j < param._dog_level_num; j++, idx++, ftex++)
00695 {
00696
00697 if(_levelFeatureNum[idx]>0)
00698 {
00699 ftex->CopyToHost(ps = p);
00700 for(int k = 0; k < _levelFeatureNum[idx]; k++, ps+=4)
00701 {
00702 ps[0] = os*(ps[0]-0.5f) + offset;
00703 ps[1] = os*(ps[1]-0.5f) + offset;
00704 ps[2] = os*ps[2];
00705 ps[3] = (float)fmod(twopi-ps[3], twopi);
00706 }
00707 p+= 4* _levelFeatureNum[idx];
00708 }
00709 }
00710 }
00711
00712
00713 if(_keypoint_index.size() > 0)
00714 {
00715 for(int i = 0; i < _featureNum; ++i)
00716 {
00717 int index = _keypoint_index[i];
00718 memcpy(&_keypoint_buffer[index*4], &keypoint_buffer2[i*4], 4 * sizeof(float));
00719 }
00720 }
00721 }
00722
00723 void PyramidCU::GenerateFeatureListCPU()
00724 {
00725
00726 GenerateFeatureList();
00727 }
00728
00729 void PyramidCU::GenerateFeatureList(int i, int j, int reduction_count, vector<int>& hbuffer)
00730 {
00731 int fcount = 0, idx = i * param._dog_level_num + j;
00732 int hist_level_num = _hpLevelNum - _pyramid_octave_first /2;
00733 int ii, k, len;
00734
00735 CuTexImage * htex, * ftex, * tex, *got;
00736 ftex = _featureTex + idx;
00737 htex = _histoPyramidTex + hist_level_num -1;
00738 tex = GetBaseLevel(_octave_min + i, DATA_KEYPOINT) + 2 + j;
00739 got = GetBaseLevel(_octave_min + i, DATA_GRAD) + 2 + j;
00740
00741 ProgramCU::InitHistogram(tex, htex);
00742
00743 for(k = 0; k < reduction_count - 1; k++, htex--)
00744 {
00745 ProgramCU::ReduceHistogram(htex, htex -1);
00746 }
00747
00748
00749 len = htex->GetImgHeight() * 4;
00750 hbuffer.resize(len);
00751 ProgramCU::FinishCUDA();
00752 htex->CopyToHost(&hbuffer[0]);
00753
00755 for(ii = 0; ii < len; ++ii) {if(!(hbuffer[ii]>= 0)) hbuffer[ii] = 0; }
00756
00757
00758 for(ii = 0; ii < len; ++ii) fcount += hbuffer[ii];
00759 SetLevelFeatureNum(idx, fcount);
00760
00761
00762 if(fcount > 0)
00763 {
00764 _featureNum += fcount;
00765 _keypoint_buffer.resize(fcount * 4);
00766
00767 int* ibuf = (int*) (&_keypoint_buffer[0]);
00768
00769 for(ii = 0; ii < len; ++ii)
00770 {
00771 int x = ii%4, y = ii / 4;
00772 for(int jj = 0 ; jj < hbuffer[ii]; ++jj, ibuf+=4)
00773 {
00774 ibuf[0] = x; ibuf[1] = y; ibuf[2] = jj; ibuf[3] = 0;
00775 }
00776 }
00777 _featureTex[idx].CopyFromHost(&_keypoint_buffer[0]);
00778
00780 ProgramCU::GenerateList(_featureTex + idx, ++htex);
00781 for(k = 2; k < reduction_count; k++)
00782 {
00783 ProgramCU::GenerateList(_featureTex + idx, ++htex);
00784 }
00785 }
00786 }
00787
00788 void PyramidCU::GenerateFeatureList()
00789 {
00790 double t1, t2;
00791 int ocount = 0, reduction_count;
00792 int reverse = (GlobalUtil::_TruncateMethod == 1);
00793
00794 vector<int> hbuffer;
00795 _featureNum = 0;
00796
00797
00798 FOR_EACH_OCTAVE(i, reverse)
00799 {
00800 CuTexImage* tex = GetBaseLevel(_octave_min + i, DATA_KEYPOINT) + 2;
00801 reduction_count = FitHistogramPyramid(tex);
00802
00803 if(GlobalUtil::_timingO)
00804 {
00805 t1 = CLOCK();
00806 ocount = 0;
00807 std::cout<<"#"<<i+_octave_min + _down_sample_factor<<":\t";
00808 }
00809
00810 FOR_EACH_LEVEL(j, reverse)
00811 {
00812 if(GlobalUtil::_TruncateMethod && GlobalUtil::_FeatureCountThreshold > 0 && _featureNum > GlobalUtil::_FeatureCountThreshold) continue;
00813
00814 GenerateFeatureList(i, j, reduction_count, hbuffer);
00815
00817 if(GlobalUtil::_timingO)
00818 {
00819 int idx = i * param._dog_level_num + j;
00820 ocount += _levelFeatureNum[idx];
00821 std::cout<< _levelFeatureNum[idx] <<"\t";
00822 }
00823 }
00824 if(GlobalUtil::_timingO)
00825 {
00826 t2 = CLOCK();
00827 std::cout << "| \t" << int(ocount) << " :\t(" << (t2 - t1) << ")\n";
00828 }
00829 }
00831 CopyGradientTex();
00833 if(GlobalUtil::_timingS)ProgramCU::FinishCUDA();
00834
00835 if(GlobalUtil::_verbose)
00836 {
00837 std::cout<<"#Features:\t"<<_featureNum<<"\n";
00838 }
00839
00840 if(ProgramCU::CheckErrorCUDA("PyramidCU::GenerateFeatureList")) SetFailStatus();
00841 }
00842
00843 GLTexImage* PyramidCU::GetLevelTexture(int octave, int level)
00844 {
00845 return GetLevelTexture(octave, level, DATA_GAUSSIAN);
00846 }
00847
00848 GLTexImage* PyramidCU::ConvertTexCU2GL(CuTexImage* tex, int dataName)
00849 {
00850
00851 GLenum format = GL_LUMINANCE;
00852 int convert_done = 1;
00853 if(_bufferPBO == 0) glGenBuffers(1, &_bufferPBO);
00854 if(_bufferTEX == NULL) _bufferTEX = new GLTexImage;
00855 switch(dataName)
00856 {
00857 case DATA_GAUSSIAN:
00858 {
00859 convert_done = tex->CopyToPBO(_bufferPBO);
00860 break;
00861 }
00862 case DATA_DOG:
00863 {
00864 CuTexImage texPBO(tex->GetImgWidth(), tex->GetImgHeight(), 1, _bufferPBO);
00865 if(texPBO._cuData == 0 || tex->_cuData == NULL) convert_done = 0;
00866 else ProgramCU::DisplayConvertDOG(tex, &texPBO);
00867 break;
00868 }
00869 case DATA_GRAD:
00870 {
00871 CuTexImage texPBO(tex->GetImgWidth(), tex->GetImgHeight(), 1, _bufferPBO);
00872 if(texPBO._cuData == 0 || tex->_cuData == NULL) convert_done = 0;
00873 else ProgramCU::DisplayConvertGRD(tex, &texPBO);
00874 break;
00875 }
00876 case DATA_KEYPOINT:
00877 {
00878 CuTexImage * dog = tex - param._level_num * _pyramid_octave_num;
00879 format = GL_RGBA;
00880 CuTexImage texPBO(tex->GetImgWidth(), tex->GetImgHeight(), 4, _bufferPBO);
00881 if(texPBO._cuData == 0 || tex->_cuData == NULL) convert_done = 0;
00882 else ProgramCU::DisplayConvertKEY(tex, dog, &texPBO);
00883 break;
00884 }
00885 default:
00886 convert_done = 0;
00887 break;
00888 }
00889
00890 if(convert_done)
00891 {
00892 _bufferTEX->InitTexture(max(_bufferTEX->GetTexWidth(), tex->GetImgWidth()), max(_bufferTEX->GetTexHeight(), tex->GetImgHeight()));
00893 _bufferTEX->CopyFromPBO(_bufferPBO, tex->GetImgWidth(), tex->GetImgHeight(), format);
00894 }else
00895 {
00896 _bufferTEX->SetImageSize(0, 0);
00897 }
00898
00899 return _bufferTEX;
00900 }
00901
00902 GLTexImage* PyramidCU::GetLevelTexture(int octave, int level, int dataName)
00903 {
00904 CuTexImage* tex = GetBaseLevel(octave, dataName) + (level - param._level_min);
00905
00906 return ConvertTexCU2GL(tex, dataName);
00907 }
00908
00909 void PyramidCU::ConvertInputToCU(GLTexInput* input)
00910 {
00911 int ws = input->GetImgWidth(), hs = input->GetImgHeight();
00912 TruncateWidth(ws);
00913
00914 if(input->_pixel_data)
00915 {
00916 _inputTex->InitTexture(ws, hs, 1);
00917 _inputTex->CopyFromHost(input->_pixel_data);
00918 }else
00919 {
00920 if(_bufferPBO == 0) glGenBuffers(1, &_bufferPBO);
00921 if(input->_rgb_converted && input->CopyToPBO(_bufferPBO, ws, hs, GL_LUMINANCE))
00922 {
00923 _inputTex->InitTexture(ws, hs, 1);
00924 _inputTex->CopyFromPBO(ws, hs, _bufferPBO);
00925 }else if(input->CopyToPBO(_bufferPBO, ws, hs))
00926 {
00927 CuTexImage texPBO(ws, hs, 4, _bufferPBO);
00928 _inputTex->InitTexture(ws, hs, 1);
00929 ProgramCU::ReduceToSingleChannel(_inputTex, &texPBO, !input->_rgb_converted);
00930 }else
00931 {
00932 std::cerr<< "Unable To Convert Intput\n";
00933 }
00934 }
00935 }
00936
00937 void PyramidCU::BuildPyramid(GLTexInput * input)
00938 {
00939
00940 USE_TIMING();
00941
00942 int i, j;
00943
00944 for ( i = _octave_min; i < _octave_min + _octave_num; i++)
00945 {
00946
00947 float* filter_sigma = param._sigma;
00948 CuTexImage *tex = GetBaseLevel(i);
00949 CuTexImage *buf = GetBaseLevel(i, DATA_KEYPOINT) +2;
00950 j = param._level_min + 1;
00951
00952 OCTAVE_START();
00953
00954 if( i == _octave_min )
00955 {
00956 ConvertInputToCU(input);
00957
00958 if(i == 0)
00959 {
00960 ProgramCU::FilterImage(tex, _inputTex, buf,
00961 param.GetInitialSmoothSigma(_octave_min + _down_sample_factor));
00962 }else
00963 {
00964 if(i < 0) ProgramCU::SampleImageU(tex, _inputTex, -i);
00965 else ProgramCU::SampleImageD(tex, _inputTex, i);
00966 ProgramCU::FilterImage(tex, tex, buf,
00967 param.GetInitialSmoothSigma(_octave_min + _down_sample_factor));
00968 }
00969 }else
00970 {
00971 ProgramCU::SampleImageD(tex, GetBaseLevel(i - 1) + param._level_ds - param._level_min);
00972 if(param._sigma_skip1 > 0)
00973 {
00974 ProgramCU::FilterImage(tex, tex, buf, param._sigma_skip1);
00975 }
00976 }
00977 LEVEL_FINISH();
00978 for( ; j <= param._level_max ; j++, tex++, filter_sigma++)
00979 {
00980
00981 ProgramCU::FilterImage(tex + 1, tex, buf, *filter_sigma);
00982 LEVEL_FINISH();
00983 }
00984 OCTAVE_FINISH();
00985 }
00986 if(GlobalUtil::_timingS) ProgramCU::FinishCUDA();
00987
00988 if(ProgramCU::CheckErrorCUDA("PyramidCU::BuildPyramid")) SetFailStatus();
00989 }
00990
00991 void PyramidCU::DetectKeypointsEX()
00992 {
00993
00994
00995 int i, j;
00996 double t0, t, ts, t1, t2;
00997
00998 if(GlobalUtil::_timingS && GlobalUtil::_verbose)ts = CLOCK();
00999
01000 for(i = _octave_min; i < _octave_min + _octave_num; i++)
01001 {
01002 CuTexImage * gus = GetBaseLevel(i) + 1;
01003 CuTexImage * dog = GetBaseLevel(i, DATA_DOG) + 1;
01004 CuTexImage * got = GetBaseLevel(i, DATA_GRAD) + 1;
01005
01006 for(j = param._level_min +1; j <= param._level_max ; j++, gus++, dog++, got++)
01007 {
01008
01009
01010 ProgramCU::ComputeDOG(gus, dog, got);
01011 }
01012 }
01013 if(GlobalUtil::_timingS && GlobalUtil::_verbose)
01014 {
01015 ProgramCU::FinishCUDA();
01016 t1 = CLOCK();
01017 }
01018
01019 for ( i = _octave_min; i < _octave_min + _octave_num; i++)
01020 {
01021 if(GlobalUtil::_timingO)
01022 {
01023 t0 = CLOCK();
01024 std::cout<<"#"<<(i + _down_sample_factor)<<"\t";
01025 }
01026 CuTexImage * dog = GetBaseLevel(i, DATA_DOG) + 2;
01027 CuTexImage * key = GetBaseLevel(i, DATA_KEYPOINT) +2;
01028
01029
01030 for( j = param._level_min +2; j < param._level_max ; j++, dog++, key++)
01031 {
01032 if(GlobalUtil::_timingL)t = CLOCK();
01033
01034
01035 ProgramCU::ComputeKEY(dog, key, param._dog_threshold, param._edge_threshold);
01036 if(GlobalUtil::_timingL)
01037 {
01038 std::cout<<(CLOCK()-t)<<"\t";
01039 }
01040 }
01041 if(GlobalUtil::_timingO)
01042 {
01043 std::cout<<"|\t"<<(CLOCK()-t0)<<"\n";
01044 }
01045 }
01046
01047 if(GlobalUtil::_timingS)
01048 {
01049 ProgramCU::FinishCUDA();
01050 if(GlobalUtil::_verbose)
01051 {
01052 t2 = CLOCK();
01053 std::cout <<"<Gradient, DOG >\t"<<(t1-ts)<<"\n"
01054 <<"<Get Keypoints >\t"<<(t2-t1)<<"\n";
01055 }
01056 }
01057 }
01058
01059 void PyramidCU::CopyGradientTex()
01060 {
01061 double ts, t1;
01062
01063 if(GlobalUtil::_timingS && GlobalUtil::_verbose)ts = CLOCK();
01064
01065 for(int i = 0, idx = 0; i < _octave_num; i++)
01066 {
01067 CuTexImage * got = GetBaseLevel(i + _octave_min, DATA_GRAD) + 1;
01068
01069 for(int j = 0; j < param._dog_level_num ; j++, got++, idx++)
01070 {
01071 if(_levelFeatureNum[idx] > 0) got->CopyToTexture2D();
01072 }
01073 }
01074 if(GlobalUtil::_timingS)
01075 {
01076 ProgramCU::FinishCUDA();
01077 if(GlobalUtil::_verbose)
01078 {
01079 t1 = CLOCK();
01080 std::cout <<"<Copy Grad/Orientation>\t"<<(t1-ts)<<"\n";
01081 }
01082 }
01083 }
01084
01085 void PyramidCU::ComputeGradient()
01086 {
01087
01088 int i, j;
01089 double ts, t1;
01090
01091 if(GlobalUtil::_timingS && GlobalUtil::_verbose)ts = CLOCK();
01092
01093 for(i = _octave_min; i < _octave_min + _octave_num; i++)
01094 {
01095 CuTexImage * gus = GetBaseLevel(i) + 1;
01096 CuTexImage * dog = GetBaseLevel(i, DATA_DOG) + 1;
01097 CuTexImage * got = GetBaseLevel(i, DATA_GRAD) + 1;
01098
01099
01100 for(j = 0; j < param._dog_level_num ; j++, gus++, dog++, got++)
01101 {
01102 ProgramCU::ComputeDOG(gus, dog, got);
01103 }
01104 }
01105 if(GlobalUtil::_timingS)
01106 {
01107 ProgramCU::FinishCUDA();
01108 if(GlobalUtil::_verbose)
01109 {
01110 t1 = CLOCK();
01111 std::cout <<"<Gradient, DOG >\t"<<(t1-ts)<<"\n";
01112 }
01113 }
01114 }
01115
01116 int PyramidCU::FitHistogramPyramid(CuTexImage* tex)
01117 {
01118 CuTexImage *htex;
01119 int hist_level_num = _hpLevelNum - _pyramid_octave_first / 2;
01120 htex = _histoPyramidTex + hist_level_num - 1;
01121 int w = (tex->GetImgWidth() + 2) >> 2;
01122 int h = tex->GetImgHeight();
01123 int count = 0;
01124 for(int k = 0; k < hist_level_num; k++, htex--)
01125 {
01126
01127 htex->InitTexture(w, h, 4);
01128 ++count;
01129 if(w == 1)
01130 break;
01131 w = (w + 3)>>2;
01132 }
01133 return count;
01134 }
01135
01136 void PyramidCU::GetFeatureOrientations()
01137 {
01138
01139 CuTexImage * ftex = _featureTex;
01140 int * count = _levelFeatureNum;
01141 float sigma, sigma_step = powf(2.0f, 1.0f/param._dog_level_num);
01142
01143 for(int i = 0; i < _octave_num; i++)
01144 {
01145 CuTexImage* got = GetBaseLevel(i + _octave_min, DATA_GRAD) + 1;
01146 CuTexImage* key = GetBaseLevel(i + _octave_min, DATA_KEYPOINT) + 2;
01147
01148 for(int j = 0; j < param._dog_level_num; j++, ftex++, count++, got++, key++)
01149 {
01150 if(*count<=0)continue;
01151
01152
01153
01154 sigma = param.GetLevelSigma(j+param._level_min+1);
01155
01156 ProgramCU::ComputeOrientation(ftex, got, key, sigma, sigma_step, _existing_keypoints);
01157 }
01158 }
01159
01160 if(GlobalUtil::_timingS)ProgramCU::FinishCUDA();
01161 if(ProgramCU::CheckErrorCUDA("PyramidCU::GetFeatureOrientations")) SetFailStatus();
01162
01163 }
01164
01165 void PyramidCU::GetSimplifiedOrientation()
01166 {
01167
01168 GetFeatureOrientations();
01169 }
01170
01171 CuTexImage* PyramidCU::GetBaseLevel(int octave, int dataName)
01172 {
01173 if(octave <_octave_min || octave > _octave_min + _octave_num) return NULL;
01174 int offset = (_pyramid_octave_first + octave - _octave_min) * param._level_num;
01175 int num = param._level_num * _pyramid_octave_num;
01176 if (dataName == DATA_ROT) dataName = DATA_GRAD;
01177 return _allPyramid + num * dataName + offset;
01178 }
01179
01180 #endif
01181