ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
PyramidCU.cpp
Go to the documentation of this file.
1 // File: PyramidCU.cpp
3 // Author: Changchang Wu
4 // Description : implementation of the PyramidCU class.
5 // CUDA-based implementation of SiftPyramid
6 //
7 // Copyright (c) 2007 University of North Carolina at Chapel Hill
8 // All Rights Reserved
9 //
10 // Permission to use, copy, modify and distribute this software and its
11 // documentation for educational, research and non-profit purposes, without
12 // fee, and without a written agreement is hereby granted, provided that the
13 // above copyright notice and the following paragraph appear in all copies.
14 //
15 // The University of North Carolina at Chapel Hill make no representations
16 // about the suitability of this software for any purpose. It is provided
17 // 'as is' without express or implied warranty.
18 //
19 // Please send BUG REPORTS to ccwu@cs.unc.edu
20 //
22 
23 #if defined(SIFTGPU_CUDA_ENABLED)
24 
25 
26 #include "GL/glew.h"
27 #include <iostream>
28 #include <vector>
29 #include <algorithm>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33 using namespace std;
34 
35 #include "GlobalUtil.h"
36 #include "GLTexImage.h"
37 #include "CuTexImage.h"
38 #include "SiftGPU.h"
39 #include "SiftPyramid.h"
40 #include "ProgramCU.h"
41 #include "PyramidCU.h"
42 
43 
44 //#include "imdebug/imdebuggl.h"
45 //#pragma comment (lib, "../lib/imdebug.lib")
46 
47 
48 
49 #define USE_TIMING() double t, t0, tt;
50 #define OCTAVE_START() if(GlobalUtil::_timingO){ t = t0 = CLOCK(); cout<<"#"<<i+_down_sample_factor<<"\t"; }
51 #define LEVEL_FINISH() if(GlobalUtil::_timingL){ ProgramCU::FinishCUDA(); tt = CLOCK();cout<<(tt-t)<<"\t"; t = CLOCK();}
52 #define OCTAVE_FINISH() if(GlobalUtil::_timingO)cout<<"|\t"<<(CLOCK()-t0)<<endl;
53 
54 
55 PyramidCU::PyramidCU(SiftParam& sp) : SiftPyramid(sp)
56 {
57  _allPyramid = NULL;
58  _histoPyramidTex = NULL;
59  _featureTex = NULL;
60  _descriptorTex = NULL;
61  _orientationTex = NULL;
62  _bufferPBO = 0;
63  _bufferTEX = NULL;
64  _inputTex = new CuTexImage();
65 
67  InitializeContext();
68 }
69 
70 PyramidCU::~PyramidCU()
71 {
72  DestroyPerLevelData();
73  DestroySharedData();
74  DestroyPyramidData();
75  if(_inputTex) delete _inputTex;
76  if(_bufferPBO) glDeleteBuffers(1, &_bufferPBO);
77  if(_bufferTEX) delete _bufferTEX;
78 }
79 
80 void PyramidCU::InitializeContext()
81 {
84 }
85 
86 void PyramidCU::InitPyramid(int w, int h, int ds)
87 {
88  int wp, hp, toobig = 0;
89  if(ds == 0)
90  {
91  //
92  TruncateWidth(w);
94  _down_sample_factor = 0;
96  {
97  wp = w >> _octave_min_default;
98  hp = h >> _octave_min_default;
99  }else
100  {
101  //can't upsample by more than 8
102  _octave_min_default = max(-3, _octave_min_default);
103  //
104  wp = w << (-_octave_min_default);
105  hp = h << (-_octave_min_default);
106  }
107  _octave_min = _octave_min_default;
108  }else
109  {
110  //must use 0 as _octave_min;
111  _octave_min = 0;
112  _down_sample_factor = ds;
113  w >>= ds;
114  h >>= ds;
116 
117  TruncateWidth(w);
118 
119  wp = w;
120  hp = h;
121 
122  }
123 
125  {
126  _octave_min ++;
127  wp >>= 1;
128  hp >>= 1;
129  toobig = 1;
130  }
131 
132  while(GlobalUtil::_MemCapGPU > 0 && GlobalUtil::_FitMemoryCap && (wp >_pyramid_width || hp > _pyramid_height)&&
133  max(max(wp, hp), max(_pyramid_width, _pyramid_height)) > 1024 * sqrt(GlobalUtil::_MemCapGPU / 110.0))
134  {
135  _octave_min ++;
136  wp >>= 1;
137  hp >>= 1;
138  toobig = 2;
139  }
140 
141 
142  if(toobig && GlobalUtil::_verbose && _octave_min > 0)
143  {
144  std::cout<<(toobig == 2 ? "[**SKIP OCTAVES**]:\tExceeding Memory Cap (-nomc)\n" :
145  "[**SKIP OCTAVES**]:\tReaching the dimension limit(-maxd)!\n");
146  }
147  //ResizePyramid(wp, hp);
148  if( wp == _pyramid_width && hp == _pyramid_height && _allocated )
149  {
150  FitPyramid(wp, hp);
151  }else if(GlobalUtil::_ForceTightPyramid || _allocated ==0)
152  {
153  ResizePyramid(wp, hp);
154  }
155  else if( wp > _pyramid_width || hp > _pyramid_height )
156  {
157  ResizePyramid(max(wp, _pyramid_width), max(hp, _pyramid_height));
158  if(wp < _pyramid_width || hp < _pyramid_height) FitPyramid(wp, hp);
159  }
160  else
161  {
162  //try use the pyramid allocated for large image on small input images
163  FitPyramid(wp, hp);
164  }
165 }
166 
167 void PyramidCU::ResizePyramid(int w, int h)
168 {
169  //
170  unsigned int totalkb = 0;
171  int _octave_num_new, input_sz, i, j;
172  //
173 
174  if(_pyramid_width == w && _pyramid_height == h && _allocated) return;
175 
176  if(w > GlobalUtil::_texMaxDim || h > GlobalUtil::_texMaxDim) return ;
177 
178  if(GlobalUtil::_verbose && GlobalUtil::_timingS) std::cout<<"[Allocate Pyramid]:\t" <<w<<"x"<<h<<endl;
179  //first octave does not change
180  _pyramid_octave_first = 0;
181 
182 
183  //compute # of octaves
184 
185  input_sz = min(w,h) ;
186  _pyramid_width = w;
187  _pyramid_height = h;
188 
189 
190 
191  //reset to preset parameters
192 
193  _octave_num_new = GlobalUtil::_octave_num_default;
194 
195  if(_octave_num_new < 1)
196  {
197  _octave_num_new = (int) floor (log ( double(input_sz))/log(2.0)) -3 ;
198  if(_octave_num_new<1 ) _octave_num_new = 1;
199  }
200 
201  if(_pyramid_octave_num != _octave_num_new)
202  {
203  //destroy the original pyramid if the # of octave changes
204  if(_octave_num >0)
205  {
206  DestroyPerLevelData();
207  DestroyPyramidData();
208  }
209  _pyramid_octave_num = _octave_num_new;
210  }
211 
212  _octave_num = _pyramid_octave_num;
213 
214  int noct = _octave_num;
215  int nlev = param._level_num;
216 
217  // //initialize the pyramid
218  if(_allPyramid==NULL) _allPyramid = new CuTexImage[ noct* nlev * DATA_NUM];
219 
220  CuTexImage * gus = GetBaseLevel(_octave_min, DATA_GAUSSIAN);
221  CuTexImage * dog = GetBaseLevel(_octave_min, DATA_DOG);
222  CuTexImage * got = GetBaseLevel(_octave_min, DATA_GRAD);
223  CuTexImage * key = GetBaseLevel(_octave_min, DATA_KEYPOINT);
224 
226 
227  for(i = 0; i< noct; i++)
228  {
229  int wa = ((w + 3) / 4) * 4;
230 
231  totalkb += ((nlev *8 -19)* (wa * h) * 4 / 1024);
232  for( j = 0; j< nlev; j++, gus++, dog++, got++, key++)
233  {
234  gus->InitTexture(wa, h); //nlev
235  if(j==0)continue;
236  dog->InitTexture(wa, h); //nlev -1
237  if( j >= 1 && j < 1 + param._dog_level_num)
238  {
239  got->InitTexture(wa, h, 2); //2 * nlev - 6
240  got->InitTexture2D();
241  }
242  if(j > 1 && j < nlev -1) key->InitTexture(wa, h, 4); // nlev -3 ; 4 * nlev - 12
243  }
244  w>>=1;
245  h>>=1;
246  }
247 
248  totalkb += ResizeFeatureStorage();
249 
250  if(ProgramCU::CheckErrorCUDA("ResizePyramid")) SetFailStatus();
251 
252  _allocated = 1;
253 
254  if(GlobalUtil::_verbose && GlobalUtil::_timingS) std::cout<<"[Allocate Pyramid]:\t" <<(totalkb/1024)<<"MB\n";
255 
256 }
257 
258 void PyramidCU::FitPyramid(int w, int h)
259 {
260  _pyramid_octave_first = 0;
261  //
262  _octave_num = GlobalUtil::_octave_num_default;
263 
264  int _octave_num_max = max(1, (int) floor (log ( double(min(w, h)))/log(2.0)) -3 );
265 
266  if(_octave_num < 1 || _octave_num > _octave_num_max)
267  {
268  _octave_num = _octave_num_max;
269  }
270 
271 
272  int pw = _pyramid_width>>1, ph = _pyramid_height>>1;
273  while(_pyramid_octave_first + _octave_num < _pyramid_octave_num &&
274  pw >= w && ph >= h)
275  {
276  _pyramid_octave_first++;
277  pw >>= 1;
278  ph >>= 1;
279  }
280 
282  int nlev = param._level_num;
283  CuTexImage * gus = GetBaseLevel(_octave_min, DATA_GAUSSIAN);
284  CuTexImage * dog = GetBaseLevel(_octave_min, DATA_DOG);
285  CuTexImage * got = GetBaseLevel(_octave_min, DATA_GRAD);
286  CuTexImage * key = GetBaseLevel(_octave_min, DATA_KEYPOINT);
287  for(int i = 0; i< _octave_num; i++)
288  {
289  int wa = ((w + 3) / 4) * 4;
290 
291  for(int j = 0; j< nlev; j++, gus++, dog++, got++, key++)
292  {
293  gus->InitTexture(wa, h); //nlev
294  if(j==0)continue;
295  dog->InitTexture(wa, h); //nlev -1
296  if( j >= 1 && j < 1 + param._dog_level_num)
297  {
298  got->InitTexture(wa, h, 2); //2 * nlev - 6
299  got->InitTexture2D();
300  }
301  if(j > 1 && j < nlev -1) key->InitTexture(wa, h, 4); // nlev -3 ; 4 * nlev - 12
302  }
303  w>>=1;
304  h>>=1;
305  }
306 }
307 
308 int PyramidCU::CheckCudaDevice(int device)
309 {
310  return ProgramCU::CheckCudaDevice(device);
311 }
312 
313 void PyramidCU::SetLevelFeatureNum(int idx, int fcount)
314 {
315  _featureTex[idx].InitTexture(fcount, 1, 4);
316  _levelFeatureNum[idx] = fcount;
317 }
318 
319 int PyramidCU::ResizeFeatureStorage()
320 {
321  int totalkb = 0;
322  if(_levelFeatureNum==NULL) _levelFeatureNum = new int[_octave_num * param._dog_level_num];
323  std::fill(_levelFeatureNum, _levelFeatureNum+_octave_num * param._dog_level_num, 0);
324 
325  int wmax = GetBaseLevel(_octave_min)->GetImgWidth();
326  int hmax = GetBaseLevel(_octave_min)->GetImgHeight();
327  int whmax = max(wmax, hmax);
328  int w, i;
329 
330  //
331  int num = (int)ceil(log(double(whmax))/log(4.0));
332 
333  if( _hpLevelNum != num)
334  {
335  _hpLevelNum = num;
336  if(_histoPyramidTex ) delete [] _histoPyramidTex;
337  _histoPyramidTex = new CuTexImage[_hpLevelNum];
338  }
339 
340  for(i = 0, w = 1; i < _hpLevelNum; i++)
341  {
342  _histoPyramidTex[i].InitTexture(w, whmax, 4);
343  w<<=2;
344  }
345 
346  // (4 ^ (_hpLevelNum) -1 / 3) pixels
347  totalkb += (((1 << (2 * _hpLevelNum)) -1) / 3 * 16 / 1024);
348 
349  //initialize the feature texture
350  int idx = 0, n = _octave_num * param._dog_level_num;
351  if(_featureTex==NULL) _featureTex = new CuTexImage[n];
352  if(GlobalUtil::_MaxOrientation >1 && GlobalUtil::_OrientationPack2==0 && _orientationTex== NULL)
353  _orientationTex = new CuTexImage[n];
354 
355 
356  for(i = 0; i < _octave_num; i++)
357  {
358  CuTexImage * tex = GetBaseLevel(i+_octave_min);
359  int fmax = int(tex->GetImgWidth() * tex->GetImgHeight()*GlobalUtil::_MaxFeaturePercent);
360  //
362  else if(fmax < 32) fmax = 32; //give it at least a space of 32 feature
363 
364  for(int j = 0; j < param._dog_level_num; j++, idx++)
365  {
366  _featureTex[idx].InitTexture(fmax, 1, 4);
367  totalkb += fmax * 16 /1024;
368  //
370  {
371  _orientationTex[idx].InitTexture(fmax, 1, 4);
372  totalkb += fmax * 16 /1024;
373  }
374  }
375  }
376 
377 
378  //this just need be initialized once
379  if(_descriptorTex==NULL)
380  {
381  //initialize feature texture pyramid
382  int fmax = _featureTex->GetImgWidth();
383  _descriptorTex = new CuTexImage;
384  totalkb += ( fmax /2);
385  _descriptorTex->InitTexture(fmax *128, 1, 1);
386  }else
387  {
388  totalkb += _descriptorTex->GetDataSize()/1024;
389  }
390  return totalkb;
391 }
392 
393 void PyramidCU::GetFeatureDescriptors()
394 {
395  //descriptors...
396  float* pd = &_descriptor_buffer[0];
397  vector<float> descriptor_buffer2;
398 
399  //use another buffer if we need to re-order the descriptors
400  if(_keypoint_index.size() > 0)
401  {
402  descriptor_buffer2.resize(_descriptor_buffer.size());
403  pd = &descriptor_buffer2[0];
404  }
405 
406  CuTexImage * got, * ftex= _featureTex;
407  for(int i = 0, idx = 0; i < _octave_num; i++)
408  {
409  got = GetBaseLevel(i + _octave_min, DATA_GRAD) + 1;
410  for(int j = 0; j < param._dog_level_num; j++, ftex++, idx++, got++)
411  {
412  if(_levelFeatureNum[idx]==0) continue;
413  ProgramCU::ComputeDescriptor(ftex, got, _descriptorTex, IsUsingRectDescription());//process
414  _descriptorTex->CopyToHost(pd); //readback descriptor
415  pd += 128*_levelFeatureNum[idx];
416  }
417  }
418 
419  if(GlobalUtil::_timingS) ProgramCU::FinishCUDA();
420 
421  if(_keypoint_index.size() > 0)
422  {
423  //put the descriptor back to the original order for keypoint list.
424  for(int i = 0; i < _featureNum; ++i)
425  {
426  int index = _keypoint_index[i];
427  memcpy(&_descriptor_buffer[index*128], &descriptor_buffer2[i*128], 128 * sizeof(float));
428  }
429  }
430 
431  if(ProgramCU::CheckErrorCUDA("PyramidCU::GetFeatureDescriptors")) SetFailStatus();
432 }
433 
434 void PyramidCU::GenerateFeatureListTex()
435 {
436 
437  vector<float> list;
438  int idx = 0;
439  const double twopi = 2.0*3.14159265358979323846;
440  float sigma_half_step = powf(2.0f, 0.5f / param._dog_level_num);
441  float octave_sigma = _octave_min>=0? float(1<<_octave_min): 1.0f/(1<<(-_octave_min));
442  float offset = GlobalUtil::_LoweOrigin? 0 : 0.5f;
443  if(_down_sample_factor>0) octave_sigma *= float(1<<_down_sample_factor);
444 
445  _keypoint_index.resize(0); // should already be 0
446  for(int i = 0; i < _octave_num; i++, octave_sigma*= 2.0f)
447  {
448  for(int j = 0; j < param._dog_level_num; j++, idx++)
449  {
450  list.resize(0);
451  float level_sigma = param.GetLevelSigma(j + param._level_min + 1) * octave_sigma;
452  float sigma_min = level_sigma / sigma_half_step;
453  float sigma_max = level_sigma * sigma_half_step;
454  int fcount = 0 ;
455  for(int k = 0; k < _featureNum; k++)
456  {
457  float * key = &_keypoint_buffer[k*4];
458  float sigmak = key[2];
460  if(IsUsingRectDescription()) sigmak = min(key[2], key[3]) / 12.0f;
461 
462  if( (sigmak >= sigma_min && sigmak < sigma_max)
463  ||(sigmak < sigma_min && i ==0 && j == 0)
464  ||(sigmak > sigma_max && i == _octave_num -1 && j == param._dog_level_num - 1))
465  {
466  //add this keypoint to the list
467  list.push_back((key[0] - offset) / octave_sigma + 0.5f);
468  list.push_back((key[1] - offset) / octave_sigma + 0.5f);
469  if(IsUsingRectDescription())
470  {
471  list.push_back(key[2] / octave_sigma);
472  list.push_back(key[3] / octave_sigma);
473  }else
474  {
475  list.push_back(key[2] / octave_sigma);
476  list.push_back((float)fmod(twopi-key[3], twopi));
477  }
478  fcount ++;
479  //save the index of keypoints
480  _keypoint_index.push_back(k);
481  }
482 
483  }
484 
485  _levelFeatureNum[idx] = fcount;
486  if(fcount==0)continue;
487  CuTexImage * ftex = _featureTex+idx;
488 
489  SetLevelFeatureNum(idx, fcount);
490  ftex->CopyFromHost(&list[0]);
491  }
492  }
493 
495  {
496  std::cout<<"#Features:\t"<<_featureNum<<"\n";
497  }
498 
499 }
500 
501 void PyramidCU::ReshapeFeatureListCPU()
502 {
503  int i, szmax =0, sz;
504  int n = param._dog_level_num*_octave_num;
505  for( i = 0; i < n; i++)
506  {
507  sz = _levelFeatureNum[i];
508  if(sz > szmax ) szmax = sz;
509  }
510  float * buffer = new float[szmax*16];
511  float * buffer1 = buffer;
512  float * buffer2 = buffer + szmax*4;
513 
514 
515 
516  _featureNum = 0;
517 
518 #ifdef NO_DUPLICATE_DOWNLOAD
519  const double twopi = 2.0*3.14159265358979323846;
520  _keypoint_buffer.resize(0);
521  float os = _octave_min>=0? float(1<<_octave_min): 1.0f/(1<<(-_octave_min));
522  if(_down_sample_factor>0) os *= float(1<<_down_sample_factor);
523  float offset = GlobalUtil::_LoweOrigin? 0 : 0.5f;
524 #endif
525 
526 
527  for(i = 0; i < n; i++)
528  {
529  if(_levelFeatureNum[i]==0)continue;
530 
531  _featureTex[i].CopyToHost(buffer1);
532 
533  int fcount =0;
534  float * src = buffer1;
535  float * des = buffer2;
536  const static double factor = 2.0*3.14159265358979323846/65535.0;
537  for(int j = 0; j < _levelFeatureNum[i]; j++, src+=4)
538  {
539  unsigned short * orientations = (unsigned short*) (&src[3]);
540  if(orientations[0] != 65535)
541  {
542  des[0] = src[0];
543  des[1] = src[1];
544  des[2] = src[2];
545  des[3] = float( factor* orientations[0]);
546  fcount++;
547  des += 4;
548  if(orientations[1] != 65535 && orientations[1] != orientations[0])
549  {
550  des[0] = src[0];
551  des[1] = src[1];
552  des[2] = src[2];
553  des[3] = float(factor* orientations[1]);
554  fcount++;
555  des += 4;
556  }
557  }
558  }
559  //texture size
560  SetLevelFeatureNum(i, fcount);
561  _featureTex[i].CopyFromHost(buffer2);
562 
563  if(fcount == 0) continue;
564 
565 #ifdef NO_DUPLICATE_DOWNLOAD
566  float oss = os * (1 << (i / param._dog_level_num));
567  _keypoint_buffer.resize((_featureNum + fcount) * 4);
568  float* ds = &_keypoint_buffer[_featureNum * 4];
569  float* fs = buffer2;
570  for(int k = 0; k < fcount; k++, ds+=4, fs+=4)
571  {
572  ds[0] = oss*(fs[0]-0.5f) + offset; //x
573  ds[1] = oss*(fs[1]-0.5f) + offset; //y
574  ds[2] = oss*fs[2]; //scale
575  ds[3] = (float)fmod(twopi-fs[3], twopi); //orientation, mirrored
576  }
577 #endif
578  _featureNum += fcount;
579  }
580  delete[] buffer;
582  {
583  std::cout<<"#Features MO:\t"<<_featureNum<<endl;
584  }
585 }
586 
587 void PyramidCU::GenerateFeatureDisplayVBO()
588 {
589  //it is weried that this part is very slow.
590  //use a big VBO to save all the SIFT box vertices
591  int nvbo = _octave_num * param._dog_level_num;
592  if(_featureDisplayVBO==NULL)
593  {
594  //initialize the vbos
595  _featureDisplayVBO = new GLuint[nvbo];
596  _featurePointVBO = new GLuint[nvbo];
597  glGenBuffers(nvbo, _featureDisplayVBO);
598  glGenBuffers(nvbo, _featurePointVBO);
599  }
600  for(int i = 0; i < nvbo; i++)
601  {
602  if(_levelFeatureNum[i]<=0)continue;
603  CuTexImage * ftex = _featureTex + i;
604  CuTexImage texPBO1( _levelFeatureNum[i]* 10, 1, 4, _featureDisplayVBO[i]);
605  CuTexImage texPBO2(_levelFeatureNum[i], 1, 4, _featurePointVBO[i]);
606  ProgramCU::DisplayKeyBox(ftex, &texPBO1);
607  ProgramCU::DisplayKeyPoint(ftex, &texPBO2);
608  }
609 }
610 
611 void PyramidCU::DestroySharedData()
612 {
613  //histogram reduction
614  if(_histoPyramidTex)
615  {
616  delete[] _histoPyramidTex;
617  _hpLevelNum = 0;
618  _histoPyramidTex = NULL;
619  }
620  //descriptor storage shared by all levels
621  if(_descriptorTex)
622  {
623  delete _descriptorTex;
624  _descriptorTex = NULL;
625  }
626  //cpu reduction buffer.
627  if(_histo_buffer)
628  {
629  delete[] _histo_buffer;
630  _histo_buffer = 0;
631  }
632 }
633 
634 void PyramidCU::DestroyPerLevelData()
635 {
636  //integers vector to store the feature numbers.
637  if(_levelFeatureNum)
638  {
639  delete [] _levelFeatureNum;
640  _levelFeatureNum = NULL;
641  }
642  //texture used to store features
643  if( _featureTex)
644  {
645  delete [] _featureTex;
646  _featureTex = NULL;
647  }
648  //texture used for multi-orientation
649  if(_orientationTex)
650  {
651  delete [] _orientationTex;
652  _orientationTex = NULL;
653  }
654  int no = _octave_num* param._dog_level_num;
655 
656  //two sets of vbos used to display the features
657  if(_featureDisplayVBO)
658  {
659  glDeleteBuffers(no, _featureDisplayVBO);
660  delete [] _featureDisplayVBO;
661  _featureDisplayVBO = NULL;
662  }
663  if( _featurePointVBO)
664  {
665  glDeleteBuffers(no, _featurePointVBO);
666  delete [] _featurePointVBO;
667  _featurePointVBO = NULL;
668  }
669 }
670 
671 void PyramidCU::DestroyPyramidData()
672 {
673  if(_allPyramid)
674  {
675  delete [] _allPyramid;
676  _allPyramid = NULL;
677  }
678 }
679 
680 void PyramidCU::DownloadKeypoints()
681 {
682  const double twopi = 2.0*3.14159265358979323846;
683  int idx = 0;
684  float * buffer = &_keypoint_buffer[0];
685  vector<float> keypoint_buffer2;
686  //use a different keypoint buffer when processing with an exisint features list
687  //without orientation information.
688  if(_keypoint_index.size() > 0)
689  {
690  keypoint_buffer2.resize(_keypoint_buffer.size());
691  buffer = &keypoint_buffer2[0];
692  }
693  float * p = buffer, *ps;
694  CuTexImage * ftex = _featureTex;
696  float os = _octave_min>=0? float(1<<_octave_min): 1.0f/(1<<(-_octave_min));
697  if(_down_sample_factor>0) os *= float(1<<_down_sample_factor);
698  float offset = GlobalUtil::_LoweOrigin? 0 : 0.5f;
700  for(int i = 0; i < _octave_num; i++, os *= 2.0f)
701  {
702 
703  for(int j = 0; j < param._dog_level_num; j++, idx++, ftex++)
704  {
705 
706  if(_levelFeatureNum[idx]>0)
707  {
708  ftex->CopyToHost(ps = p);
709  for(int k = 0; k < _levelFeatureNum[idx]; k++, ps+=4)
710  {
711  ps[0] = os*(ps[0]-0.5f) + offset; //x
712  ps[1] = os*(ps[1]-0.5f) + offset; //y
713  ps[2] = os*ps[2];
714  ps[3] = (float)fmod(twopi-ps[3], twopi); //orientation, mirrored
715  }
716  p+= 4* _levelFeatureNum[idx];
717  }
718  }
719  }
720 
721  //put the feature into their original order for existing keypoint
722  if(_keypoint_index.size() > 0)
723  {
724  for(int i = 0; i < _featureNum; ++i)
725  {
726  int index = _keypoint_index[i];
727  memcpy(&_keypoint_buffer[index*4], &keypoint_buffer2[i*4], 4 * sizeof(float));
728  }
729  }
730 }
731 
732 void PyramidCU::GenerateFeatureListCPU()
733 {
734  //no cpu version provided
735  GenerateFeatureList();
736 }
737 
738 void PyramidCU::GenerateFeatureList(int i, int j, int reduction_count, vector<int>& hbuffer)
739 {
740  int fcount = 0, idx = i * param._dog_level_num + j;
741  int hist_level_num = _hpLevelNum - _pyramid_octave_first /2;
742  int ii, k, len;
743 
744  CuTexImage * htex, * ftex, * tex, *got;
745  ftex = _featureTex + idx;
746  htex = _histoPyramidTex + hist_level_num -1;
747  tex = GetBaseLevel(_octave_min + i, DATA_KEYPOINT) + 2 + j;
748  got = GetBaseLevel(_octave_min + i, DATA_GRAD) + 2 + j;
749 
750  ProgramCU::InitHistogram(tex, htex);
751 
752  for(k = 0; k < reduction_count - 1; k++, htex--)
753  {
754  ProgramCU::ReduceHistogram(htex, htex -1);
755  }
756 
757  //htex has the row reduction result
758  len = htex->GetImgHeight() * 4;
759  hbuffer.resize(len);
760  ProgramCU::FinishCUDA();
761  htex->CopyToHost(&hbuffer[0]);
762 
764  for(ii = 0; ii < len; ++ii) {if(!(hbuffer[ii]>= 0)) hbuffer[ii] = 0; }//?
765 
766 
767  for(ii = 0; ii < len; ++ii) fcount += hbuffer[ii];
768  SetLevelFeatureNum(idx, fcount);
769 
770  //build the feature list
771  if(fcount > 0)
772  {
773  _featureNum += fcount;
774  _keypoint_buffer.resize(fcount * 4);
775  //vector<int> ikbuf(fcount*4);
776  int* ibuf = (int*) (&_keypoint_buffer[0]);
777 
778  for(ii = 0; ii < len; ++ii)
779  {
780  int x = ii%4, y = ii / 4;
781  for(int jj = 0 ; jj < hbuffer[ii]; ++jj, ibuf+=4)
782  {
783  ibuf[0] = x; ibuf[1] = y; ibuf[2] = jj; ibuf[3] = 0;
784  }
785  }
786  _featureTex[idx].CopyFromHost(&_keypoint_buffer[0]);
787 
789  ProgramCU::GenerateList(_featureTex + idx, ++htex);
790  for(k = 2; k < reduction_count; k++)
791  {
792  ProgramCU::GenerateList(_featureTex + idx, ++htex);
793  }
794  }
795 }
796 
797 void PyramidCU::GenerateFeatureList()
798 {
799  double t1, t2;
800  int ocount = 0, reduction_count;
801  int reverse = (GlobalUtil::_TruncateMethod == 1);
802 
803  vector<int> hbuffer;
804  _featureNum = 0;
805 
806  //for(int i = 0, idx = 0; i < _octave_num; i++)
807  FOR_EACH_OCTAVE(i, reverse)
808  {
809  CuTexImage* tex = GetBaseLevel(_octave_min + i, DATA_KEYPOINT) + 2;
810  reduction_count = FitHistogramPyramid(tex);
811 
813  {
814  t1 = CLOCK();
815  ocount = 0;
816  std::cout<<"#"<<i+_octave_min + _down_sample_factor<<":\t";
817  }
818  //for(int j = 0; j < param._dog_level_num; j++, idx++)
819  FOR_EACH_LEVEL(j, reverse)
820  {
821  // (mgprt 20/06/2018) _levelFeatureNum can still contain old
822  // values for these levels, so if we do not reset them the sum
823  // of level features will not match the absolte number of features.
825  int idx = i * param._dog_level_num + j;
826  _levelFeatureNum[idx] = 0;
827  continue;
828  }
829 
830  GenerateFeatureList(i, j, reduction_count, hbuffer);
831 
834  {
835  int idx = i * param._dog_level_num + j;
836  ocount += _levelFeatureNum[idx];
837  std::cout<< _levelFeatureNum[idx] <<"\t";
838  }
839  }
841  {
842  t2 = CLOCK();
843  std::cout << "| \t" << int(ocount) << " :\t(" << (t2 - t1) << ")\n";
844  }
845  }
847  CopyGradientTex();
849  if(GlobalUtil::_timingS)ProgramCU::FinishCUDA();
850 
852  {
853  std::cout<<"#Features:\t"<<_featureNum<<"\n";
854  }
855 
856  if(ProgramCU::CheckErrorCUDA("PyramidCU::GenerateFeatureList")) SetFailStatus();
857 }
858 
859 GLTexImage* PyramidCU::GetLevelTexture(int octave, int level)
860 {
861  return GetLevelTexture(octave, level, DATA_GAUSSIAN);
862 }
863 
864 GLTexImage* PyramidCU::ConvertTexCU2GL(CuTexImage* tex, int dataName)
865 {
866 
867  GLenum format = GL_LUMINANCE;
868  int convert_done = 1;
869  if(_bufferPBO == 0) glGenBuffers(1, &_bufferPBO);
870  if(_bufferTEX == NULL) _bufferTEX = new GLTexImage;
871  switch(dataName)
872  {
873  case DATA_GAUSSIAN:
874  {
875  convert_done = tex->CopyToPBO(_bufferPBO);
876  break;
877  }
878  case DATA_DOG:
879  {
880  CuTexImage texPBO(tex->GetImgWidth(), tex->GetImgHeight(), 1, _bufferPBO);
881  if(texPBO._cuData == 0 || tex->_cuData == NULL) convert_done = 0;
882  else ProgramCU::DisplayConvertDOG(tex, &texPBO);
883  break;
884  }
885  case DATA_GRAD:
886  {
887  CuTexImage texPBO(tex->GetImgWidth(), tex->GetImgHeight(), 1, _bufferPBO);
888  if(texPBO._cuData == 0 || tex->_cuData == NULL) convert_done = 0;
889  else ProgramCU::DisplayConvertGRD(tex, &texPBO);
890  break;
891  }
892  case DATA_KEYPOINT:
893  {
894  CuTexImage * dog = tex - param._level_num * _pyramid_octave_num;
895  format = GL_RGBA;
896  CuTexImage texPBO(tex->GetImgWidth(), tex->GetImgHeight(), 4, _bufferPBO);
897  if(texPBO._cuData == 0 || tex->_cuData == NULL) convert_done = 0;
898  else ProgramCU::DisplayConvertKEY(tex, dog, &texPBO);
899  break;
900  }
901  default:
902  convert_done = 0;
903  break;
904  }
905 
906  if(convert_done)
907  {
908  _bufferTEX->InitTexture(max(_bufferTEX->GetTexWidth(), tex->GetImgWidth()), max(_bufferTEX->GetTexHeight(), tex->GetImgHeight()));
909  _bufferTEX->CopyFromPBO(_bufferPBO, tex->GetImgWidth(), tex->GetImgHeight(), format);
910  }else
911  {
912  _bufferTEX->SetImageSize(0, 0);
913  }
914 
915  return _bufferTEX;
916 }
917 
918 GLTexImage* PyramidCU::GetLevelTexture(int octave, int level, int dataName)
919 {
920  CuTexImage* tex = GetBaseLevel(octave, dataName) + (level - param._level_min);
921  //CuTexImage* gus = GetBaseLevel(octave, DATA_GAUSSIAN) + (level - param._level_min);
922  return ConvertTexCU2GL(tex, dataName);
923 }
924 
925 void PyramidCU::ConvertInputToCU(GLTexInput* input)
926 {
927  int ws = input->GetImgWidth(), hs = input->GetImgHeight();
928  TruncateWidth(ws);
929  //copy the input image to pixel buffer object
930  if(input->_pixel_data)
931  {
932  _inputTex->InitTexture(ws, hs, 1);
933  _inputTex->CopyFromHost(input->_pixel_data);
934  }else
935  {
936  if(_bufferPBO == 0) glGenBuffers(1, &_bufferPBO);
937  if(input->_rgb_converted && input->CopyToPBO(_bufferPBO, ws, hs, GL_LUMINANCE))
938  {
939  _inputTex->InitTexture(ws, hs, 1);
940  _inputTex->CopyFromPBO(ws, hs, _bufferPBO);
941  }else if(input->CopyToPBO(_bufferPBO, ws, hs))
942  {
943  CuTexImage texPBO(ws, hs, 4, _bufferPBO);
944  _inputTex->InitTexture(ws, hs, 1);
945  ProgramCU::ReduceToSingleChannel(_inputTex, &texPBO, !input->_rgb_converted);
946  }else
947  {
948  std::cerr<< "Unable To Convert Intput\n";
949  }
950  }
951 }
952 
953 void PyramidCU::BuildPyramid(GLTexInput * input)
954 {
955 
956  USE_TIMING();
957 
958  int i, j;
959 
960  for ( i = _octave_min; i < _octave_min + _octave_num; i++)
961  {
962 
963  float* filter_sigma = param._sigma;
964  CuTexImage *tex = GetBaseLevel(i);
965  CuTexImage *buf = GetBaseLevel(i, DATA_KEYPOINT) +2;
966  j = param._level_min + 1;
967 
968  OCTAVE_START();
969 
970  if( i == _octave_min )
971  {
972  ConvertInputToCU(input);
973 
974  if(i == 0)
975  {
976  ProgramCU::FilterImage(tex, _inputTex, buf,
977  param.GetInitialSmoothSigma(_octave_min + _down_sample_factor));
978  }else
979  {
980  if(i < 0) ProgramCU::SampleImageU(tex, _inputTex, -i);
981  else ProgramCU::SampleImageD(tex, _inputTex, i);
982  ProgramCU::FilterImage(tex, tex, buf,
983  param.GetInitialSmoothSigma(_octave_min + _down_sample_factor));
984  }
985  }else
986  {
987  ProgramCU::SampleImageD(tex, GetBaseLevel(i - 1) + param._level_ds - param._level_min);
988  if(param._sigma_skip1 > 0)
989  {
990  ProgramCU::FilterImage(tex, tex, buf, param._sigma_skip1);
991  }
992  }
993  LEVEL_FINISH();
994  for( ; j <= param._level_max ; j++, tex++, filter_sigma++)
995  {
996  // filtering
997  ProgramCU::FilterImage(tex + 1, tex, buf, *filter_sigma);
998  LEVEL_FINISH();
999  }
1000  OCTAVE_FINISH();
1001  }
1002  if(GlobalUtil::_timingS) ProgramCU::FinishCUDA();
1003 
1004  if(ProgramCU::CheckErrorCUDA("PyramidCU::BuildPyramid")) SetFailStatus();
1005 }
1006 
1007 void PyramidCU::DetectKeypointsEX()
1008 {
1009 
1010 
1011  int i, j;
1012  double t0, t, ts, t1, t2;
1013 
1014  if(GlobalUtil::_timingS && GlobalUtil::_verbose)ts = CLOCK();
1015 
1016  for(i = _octave_min; i < _octave_min + _octave_num; i++)
1017  {
1018  CuTexImage * gus = GetBaseLevel(i) + 1;
1019  CuTexImage * dog = GetBaseLevel(i, DATA_DOG) + 1;
1020  CuTexImage * got = GetBaseLevel(i, DATA_GRAD) + 1;
1021  //compute the gradient
1022  for(j = param._level_min +1; j <= param._level_max ; j++, gus++, dog++, got++)
1023  {
1024  //input: gus and gus -1
1025  //output: gradient, dog, orientation
1026  ProgramCU::ComputeDOG(gus, dog, got);
1027  }
1028  }
1030  {
1031  ProgramCU::FinishCUDA();
1032  t1 = CLOCK();
1033  }
1034 
1035  for ( i = _octave_min; i < _octave_min + _octave_num; i++)
1036  {
1038  {
1039  t0 = CLOCK();
1040  std::cout<<"#"<<(i + _down_sample_factor)<<"\t";
1041  }
1042  CuTexImage * dog = GetBaseLevel(i, DATA_DOG) + 2;
1043  CuTexImage * key = GetBaseLevel(i, DATA_KEYPOINT) +2;
1044 
1045 
1046  for( j = param._level_min +2; j < param._level_max ; j++, dog++, key++)
1047  {
1048  if(GlobalUtil::_timingL)t = CLOCK();
1049  //input, dog, dog + 1, dog -1
1050  //output, key
1051  ProgramCU::ComputeKEY(dog, key, param._dog_threshold, param._edge_threshold);
1053  {
1054  std::cout<<(CLOCK()-t)<<"\t";
1055  }
1056  }
1058  {
1059  std::cout<<"|\t"<<(CLOCK()-t0)<<"\n";
1060  }
1061  }
1062 
1064  {
1065  ProgramCU::FinishCUDA();
1067  {
1068  t2 = CLOCK();
1069  std::cout <<"<Gradient, DOG >\t"<<(t1-ts)<<"\n"
1070  <<"<Get Keypoints >\t"<<(t2-t1)<<"\n";
1071  }
1072  }
1073 }
1074 
1075 void PyramidCU::CopyGradientTex()
1076 {
1077  double ts, t1;
1078 
1079  if(GlobalUtil::_timingS && GlobalUtil::_verbose)ts = CLOCK();
1080 
1081  for(int i = 0, idx = 0; i < _octave_num; i++)
1082  {
1083  CuTexImage * got = GetBaseLevel(i + _octave_min, DATA_GRAD) + 1;
1084  //compute the gradient
1085  for(int j = 0; j < param._dog_level_num ; j++, got++, idx++)
1086  {
1087  if(_levelFeatureNum[idx] > 0) got->CopyToTexture2D();
1088  }
1089  }
1091  {
1092  ProgramCU::FinishCUDA();
1094  {
1095  t1 = CLOCK();
1096  std::cout <<"<Copy Grad/Orientation>\t"<<(t1-ts)<<"\n";
1097  }
1098  }
1099 }
1100 
1101 void PyramidCU::ComputeGradient()
1102 {
1103 
1104  int i, j;
1105  double ts, t1;
1106 
1107  if(GlobalUtil::_timingS && GlobalUtil::_verbose)ts = CLOCK();
1108 
1109  for(i = _octave_min; i < _octave_min + _octave_num; i++)
1110  {
1111  CuTexImage * gus = GetBaseLevel(i) + 1;
1112  CuTexImage * dog = GetBaseLevel(i, DATA_DOG) + 1;
1113  CuTexImage * got = GetBaseLevel(i, DATA_GRAD) + 1;
1114 
1115  //compute the gradient
1116  for(j = 0; j < param._dog_level_num ; j++, gus++, dog++, got++)
1117  {
1118  ProgramCU::ComputeDOG(gus, dog, got);
1119  }
1120  }
1122  {
1123  ProgramCU::FinishCUDA();
1125  {
1126  t1 = CLOCK();
1127  std::cout <<"<Gradient, DOG >\t"<<(t1-ts)<<"\n";
1128  }
1129  }
1130 }
1131 
1132 int PyramidCU::FitHistogramPyramid(CuTexImage* tex)
1133 {
1134  CuTexImage *htex;
1135  int hist_level_num = _hpLevelNum - _pyramid_octave_first / 2;
1136  htex = _histoPyramidTex + hist_level_num - 1;
1137  int w = (tex->GetImgWidth() + 2) >> 2;
1138  int h = tex->GetImgHeight();
1139  int count = 0;
1140  for(int k = 0; k < hist_level_num; k++, htex--)
1141  {
1142  //htex->SetImageSize(w, h);
1143  htex->InitTexture(w, h, 4);
1144  ++count;
1145  if(w == 1)
1146  break;
1147  w = (w + 3)>>2;
1148  }
1149  return count;
1150 }
1151 
1152 void PyramidCU::GetFeatureOrientations()
1153 {
1154 
1155  CuTexImage * ftex = _featureTex;
1156  int * count = _levelFeatureNum;
1157  float sigma, sigma_step = powf(2.0f, 1.0f/param._dog_level_num);
1158 
1159  for(int i = 0; i < _octave_num; i++)
1160  {
1161  CuTexImage* got = GetBaseLevel(i + _octave_min, DATA_GRAD) + 1;
1162  CuTexImage* key = GetBaseLevel(i + _octave_min, DATA_KEYPOINT) + 2;
1163 
1164  for(int j = 0; j < param._dog_level_num; j++, ftex++, count++, got++, key++)
1165  {
1166  if(*count<=0)continue;
1167 
1168  //if(ftex->GetImgWidth() < *count) ftex->InitTexture(*count, 1, 4);
1169 
1170  sigma = param.GetLevelSigma(j+param._level_min+1);
1171 
1172  ProgramCU::ComputeOrientation(ftex, got, key, sigma, sigma_step, _existing_keypoints);
1173  }
1174  }
1175 
1176  if(GlobalUtil::_timingS)ProgramCU::FinishCUDA();
1177  if(ProgramCU::CheckErrorCUDA("PyramidCU::GetFeatureOrientations")) SetFailStatus();
1178 
1179 }
1180 
1181 void PyramidCU::GetSimplifiedOrientation()
1182 {
1183  //no simplified orientation
1184  GetFeatureOrientations();
1185 }
1186 
1187 CuTexImage* PyramidCU::GetBaseLevel(int octave, int dataName)
1188 {
1189  if(octave <_octave_min || octave > _octave_min + _octave_num) return NULL;
1190  int offset = (_pyramid_octave_first + octave - _octave_min) * param._level_num;
1191  int num = param._level_num * _pyramid_octave_num;
1192  if (dataName == DATA_ROT) dataName = DATA_GRAD;
1193  return _allPyramid + num * dataName + offset;
1194 }
1195 
1196 #endif
filament::Texture::InternalFormat format
int count
int offset
#define USE_TIMING()
Definition: PyramidGL.cpp:50
#define LEVEL_FINISH()
Definition: PyramidGL.cpp:52
#define OCTAVE_START()
Definition: PyramidGL.cpp:51
#define OCTAVE_FINISH()
Definition: PyramidGL.cpp:53
#define FOR_EACH_OCTAVE(i, R)
Definition: SiftPyramid.h:183
#define FOR_EACH_LEVEL(j, R)
Definition: SiftPyramid.h:184
#define NULL
void CopyFromHost(const void *buf)
void CopyToTexture2D()
void CopyToHost(void *buf)
int GetImgWidth()
Definition: CuTexImage.h:64
void * _cuData
Definition: CuTexImage.h:34
virtual bool InitTexture(int width, int height, int nchannel=1)
int GetImgHeight()
Definition: CuTexImage.h:65
int CopyToPBO(GLuint pbo)
int GetImgHeight()
Definition: GLTexImage.h:80
int CopyToPBO(GLuint pbo, int width, int height, GLenum format=GL_RGBA)
int GetImgWidth()
Definition: GLTexImage.h:79
const void * _pixel_data
Definition: GLTexImage.h:104
int _rgb_converted
Definition: GLTexImage.h:99
static int _TruncateMethod
Definition: GlobalUtil.h:74
static int _octave_num_default
Definition: GlobalUtil.h:79
static int _octave_min_default
Definition: GlobalUtil.h:78
static int _timingL
Definition: GlobalUtil.h:47
static int _OrientationPack2
Definition: GlobalUtil.h:60
static int _verbose
Definition: GlobalUtil.h:44
static int _FeatureCountThreshold
Definition: GlobalUtil.h:90
static int _LoweOrigin
Definition: GlobalUtil.h:85
static int _ForceTightPyramid
Definition: GlobalUtil.h:77
static int _texMaxDim
Definition: GlobalUtil.h:39
static int _timingS
Definition: GlobalUtil.h:45
static float _MaxFeaturePercent
Definition: GlobalUtil.h:66
static int _FitMemoryCap
Definition: GlobalUtil.h:43
static int _MaxLevelFeatureNum
Definition: GlobalUtil.h:67
static int _MemCapGPU
Definition: GlobalUtil.h:42
static int _MaxOrientation
Definition: GlobalUtil.h:59
static int _timingO
Definition: GlobalUtil.h:46
static int _GoodOpenGL
Definition: GlobalUtil.h:83
static void InitGLParam(int NotTargetGL=0)
Definition: GlobalUtil.cpp:319
int min(int a, int b)
Definition: cutil_math.h:53
int max(int a, int b)
Definition: cutil_math.h:48
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Definition: MiniVec.h:89
int CheckErrorCUDA(const char *location)
Definition: Eigen.h:85