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
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
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
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
00180 _pyramid_octave_first = 0;
00181
00182
00183
00184
00185 input_sz = min(w,h) ;
00186 _pyramid_width = w;
00187 _pyramid_height = h;
00188
00189
00190
00191
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
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
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);
00235 if(j==0)continue;
00236 dog->InitTexture(wa, h);
00237 if( j >= 1 && j < 1 + param._dog_level_num)
00238 {
00239 got->InitTexture(wa, h, 2);
00240 got->InitTexture2D();
00241 }
00242 if(j > 1 && j < nlev -1) key->InitTexture(wa, h, 4);
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);
00294 if(j==0)continue;
00295 dog->InitTexture(wa, h);
00296 if( j >= 1 && j < 1 + param._dog_level_num)
00297 {
00298 got->InitTexture(wa, h, 2);
00299 got->InitTexture2D();
00300 }
00301 if(j > 1 && j < nlev -1) key->InitTexture(wa, h, 4);
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
00347 totalkb += (((1 << (2 * _hpLevelNum)) -1) / 3 * 16 / 1024);
00348
00349
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;
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
00379 if(_descriptorTex==NULL)
00380 {
00381
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
00396 float* pd = &_descriptor_buffer[0];
00397 vector<float> descriptor_buffer2;
00398
00399
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());
00414 _descriptorTex->CopyToHost(pd);
00415 pd += 128*_levelFeatureNum[idx];
00416 }
00417 }
00418
00419 if(GlobalUtil::_timingS) ProgramCU::FinishCUDA();
00420
00421 if(_keypoint_index.size() > 0)
00422 {
00423
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);
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
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
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
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;
00573 ds[1] = oss*(fs[1]-0.5f) + offset;
00574 ds[2] = oss*fs[2];
00575 ds[3] = (float)fmod(twopi-fs[3], twopi);
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
00590
00591 int nvbo = _octave_num * param._dog_level_num;
00592 if(_featureDisplayVBO==NULL)
00593 {
00594
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
00614 if(_histoPyramidTex)
00615 {
00616 delete[] _histoPyramidTex;
00617 _hpLevelNum = 0;
00618 _histoPyramidTex = NULL;
00619 }
00620
00621 if(_descriptorTex)
00622 {
00623 delete _descriptorTex;
00624 _descriptorTex = NULL;
00625 }
00626
00627 if(_histo_buffer)
00628 {
00629 delete[] _histo_buffer;
00630 _histo_buffer = 0;
00631 }
00632 }
00633
00634 void PyramidCU::DestroyPerLevelData()
00635 {
00636
00637 if(_levelFeatureNum)
00638 {
00639 delete [] _levelFeatureNum;
00640 _levelFeatureNum = NULL;
00641 }
00642
00643 if( _featureTex)
00644 {
00645 delete [] _featureTex;
00646 _featureTex = NULL;
00647 }
00648
00649 if(_orientationTex)
00650 {
00651 delete [] _orientationTex;
00652 _orientationTex = NULL;
00653 }
00654 int no = _octave_num* param._dog_level_num;
00655
00656
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
00687
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;
00712 ps[1] = os*(ps[1]-0.5f) + offset;
00713 ps[2] = os*ps[2];
00714 ps[3] = (float)fmod(twopi-ps[3], twopi);
00715 }
00716 p+= 4* _levelFeatureNum[idx];
00717 }
00718 }
00719 }
00720
00721
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
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
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
00771 if(fcount > 0)
00772 {
00773 _featureNum += fcount;
00774 _keypoint_buffer.resize(fcount * 4);
00775
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
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
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
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
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
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
01015 for(j = param._level_min +1; j <= param._level_max ; j++, gus++, dog++, got++)
01016 {
01017
01018
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
01043
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
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
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
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
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
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