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