pyramidgl.cpp
来自「SiftGPU is an implementation of SIFT [1]」· C++ 代码 · 共 2,545 行 · 第 1/5 页
CPP
2,545 行
_featureTex[idx].InitTexture(fw, fh, 0);
_featureTex[idx].AttachToFBO(0);
//
if(_orientationTex)
{
_orientationTex[idx].InitTexture(fw, fh, 0);
_orientationTex[idx].AttachToFBO(0);
}
}
totalkb += fw * fh * 16 * param._dog_level_num * (_orientationTex? 2 : 1) /1024;
}
//this just need be initialized once
if(_descriptorTex==NULL)
{
//initialize feature texture pyramid
wmax = _featureTex->GetImgWidth();
hmax = _featureTex->GetImgHeight();
int nf, ns;
if(GlobalUtil::_DescriptorPPT)
{
//32*4 = 128.
nf = 32 / GlobalUtil::_DescriptorPPT; // how many textures we need
ns = max(4, GlobalUtil::_DescriptorPPT); // how many point in one texture for one descriptor
}else
{
//at least one, resue for visualization and other work
nf = 1; ns = 4;
}
//
_alignment = ns;
//
_descriptorTex = new GLTexImage[nf];
int fw, fh;
GetAlignedStorageSize(hmax*wmax* max(ns, 10), _alignment, fw, fh);
if(fh < hmax ) fh = hmax;
if(fw < wmax ) fw = wmax;
totalkb += ( fw * fh * nf * 16 /1024);
for(i =0; i < nf; i++)
{
_descriptorTex[i].InitTexture(fw, fh);
}
}else
{
int nf = GlobalUtil::_DescriptorPPT? 32 / GlobalUtil::_DescriptorPPT: 1;
totalkb += nf * _descriptorTex[0].GetTexWidth() * _descriptorTex[0].GetTexHeight() * 16 /1024;
}
return totalkb;
}
void PyramidNaive::BuildPyramid(GLTexInput *input)
{
//
USE_TIMING();
int i, j;
GLTexPacked * tex;
FilterProgram ** filter;
FrameBufferObject fbo;
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
input->FitTexViewPort();
for ( i = _octave_min; i < _octave_min + _octave_num; i++)
{
tex = (GLTexPacked*)GetBaseLevel(i);
j = param._level_min + 1;
filter = ShaderMan::f_gaussian_step;
OCTAVE_START();
if( i == _octave_min )
{
if(i < 0)
{
TextureUpSample(tex, input, 1<<(-i) );
}else
{
//image might have been already down-sampled by cpu code
TextureDownSample(tex, input, 1<<i);
}
//
if(ShaderMan::f_gaussian_skip0)
{
ShaderMan::f_gaussian_skip0->RunFilter(tex, tex, NULL);
}
LEVEL_FINISH();
}else
{
TextureDownSample(tex, GetLevelTexture(i-1, param._level_ds));
LEVEL_FINISH();
if(ShaderMan::f_gaussian_skip1)
{
ShaderMan::f_gaussian_skip1->RunFilter(tex, tex, NULL);
LEVEL_FINISH();
}
}
for( ; j <= param._level_max ; j++, tex++, filter++)
{
// filtering
(*filter)->RunFilter(tex+1, tex, NULL);
LEVEL_FINISH();
}
OCTAVE_FINISH();
}
if(GlobalUtil::_timingS) glFinish();
UnloadProgram();
}
GLTexImage* PyramidNaive::GetLevelTexture(int octave, int level, int dataName)
{
if(octave <_octave_min || octave > _octave_min + _octave_num) return NULL;
switch(dataName)
{
case DATA_GAUSSIAN:
case DATA_DOG:
case DATA_GRAD:
case DATA_ROT:
return _texPyramid+ (_pyramid_octave_first + octave - _octave_min) * param._level_num + (level - param._level_min);
case DATA_KEYPOINT:
return _auxPyramid + (_pyramid_octave_first + octave - _octave_min) * param._level_num + (level - param._level_min);
default:
return NULL;
}
}
GLTexImage* PyramidNaive::GetLevelTexture(int octave, int level)
{
return _texPyramid+ (_pyramid_octave_first + octave - _octave_min) * param._level_num
+ (level - param._level_min);
}
//in the packed implementation
// DATA_GAUSSIAN, DATA_DOG, DATA_GAD will be stored in different textures.
GLTexImage* PyramidNaive::GetBaseLevel(int octave, int dataName)
{
if(octave <_octave_min || octave > _octave_min + _octave_num) return NULL;
switch(dataName)
{
case DATA_GAUSSIAN:
case DATA_DOG:
case DATA_GRAD:
case DATA_ROT:
return _texPyramid+ (_pyramid_octave_first + octave - _octave_min) * param._level_num;
case DATA_KEYPOINT:
return _auxPyramid + (_pyramid_octave_first + octave - _octave_min) * param._level_num;
default:
return NULL;
}
}
void PyramidNaive::ComputeGradient()
{
int i, j;
double ts, t1;
GLTexImage * tex;
FrameBufferObject fbo;
if(GlobalUtil::_timingS && GlobalUtil::_verbose)ts = CLOCK();
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
for ( i = _octave_min; i < _octave_min + _octave_num; i++)
{
for( j = param._level_min + GlobalUtil::_GradientLevelOffset ; j < param._level_max ; j++)
{
tex = GetLevelTexture(i, j);
tex->FitTexViewPort();
tex->AttachToFBO(0);
tex->BindTex();
ShaderMan::UseShaderGradientPass();
tex->DrawQuadMT4();
}
}
if(GlobalUtil::_timingS && GlobalUtil::_verbose)
{
glFinish();
t1 = CLOCK();
std::cout<<"<Compute Gradient>\t"<<(t1-ts)<<"\n";
}
UnloadProgram();
GLTexImage::UnbindMultiTex(3);
fbo.UnattachTex(GL_COLOR_ATTACHMENT1_EXT);
}
//keypoint detection with subpixel localization
void PyramidNaive::DetectKeypointsEX()
{
//
int i, j;
double t0, t, ts, t1, t2;
GLTexImage * tex, *aux;
FrameBufferObject fbo;
if(GlobalUtil::_timingS && GlobalUtil::_verbose)ts = CLOCK();
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
//extra gradient data required for visualization or special parameter
if(GlobalUtil::_UseSiftGPUEX || GlobalUtil::_GradientLevelOffset ==1)
{
int levels[2] = {param._level_min +1, param._level_max};
int nlevel = GlobalUtil::_UseSiftGPUEX ? 2 : 1;
for ( i = _octave_min; i < _octave_min + _octave_num; i++)
{
for( j =0; j < nlevel ; j++)
{
tex = GetLevelTexture(i, levels[j]);
tex->FitTexViewPort();
tex->AttachToFBO(0);
tex->BindTex();
ShaderMan::UseShaderGradientPass();
tex->DrawQuadMT4();
}
}
}
if(GlobalUtil::_timingS && GlobalUtil::_verbose)
{
glFinish();
t1 = CLOCK();
}
GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
glDrawBuffers(2, buffers);
for ( i = _octave_min; i < _octave_min + _octave_num; i++)
{
if(GlobalUtil::_timingO)
{
t0 = CLOCK();
std::cout<<"#"<<(i + _down_sample_factor)<<"\t";
}
tex = GetBaseLevel(i) + 2;
aux = GetBaseLevel(i, DATA_KEYPOINT) +2;
aux->FitTexViewPort();
for( j = param._level_min +2; j < param._level_max ; j++, aux++, tex++)
{
if(GlobalUtil::_timingL)t = CLOCK();
tex->AttachToFBO(0);
aux->AttachToFBO(1);
glActiveTexture(GL_TEXTURE0);
tex->BindTex();
glActiveTexture(GL_TEXTURE1);
(tex+1)->BindTex();
glActiveTexture(GL_TEXTURE2);
(tex-1)->BindTex();
ShaderMan::UseShaderKeypoint((tex+1)->GetTexID(), (tex-1)->GetTexID());
aux->DrawQuadMT8();
if(GlobalUtil::_timingL)
{
glFinish();
std::cout<<(CLOCK()-t)<<"\t";
}
tex->DetachFBO(0);
aux->DetachFBO(1);
}
if(GlobalUtil::_timingO)
{
std::cout<<"|\t"<<(CLOCK()-t0)<<"\n";
}
}
if(GlobalUtil::_timingS)
{
glFinish();
t2 = CLOCK();
if(GlobalUtil::_verbose)
std::cout <<"<Get Keypoints .. >\t"<<(t2-t1)<<"\n"
<<"<Extra Gradient.. >\t"<<(t1-ts)<<"\n";
}
UnloadProgram();
GLTexImage::UnbindMultiTex(3);
fbo.UnattachTex(GL_COLOR_ATTACHMENT1_EXT);
}
//generate feature list on GPU
void PyramidNaive::GenerateFeatureList()
{
//generate the histogram0pyramid
FrameBufferObject fbo;
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
GLTexImage * htex, * ftex, * tex;
double t1, t2, t3, ot1, ot2, ts1 = 0, ts2 = 0;
int ocount, idx = 0;
int hist_level_num = _hpLevelNum - _pyramid_octave_first;
int hist_skip_gpu = GlobalUtil::_ListGenSkipGPU;
_featureNum = 0;
FitHistogramPyramid();
for(int i = 0; i < _octave_num; i++)
{
tex = GetBaseLevel(_octave_min + i, DATA_KEYPOINT) + 2;
//output
if(GlobalUtil::_timingO)
{
ot1 = ot2 = 0;
ocount = 0;
std::cout<<"#"<<i+_octave_min + _down_sample_factor<<":\t";
}
for(int j = 0; j < param._dog_level_num; j++, tex++, idx++)
{
float fcount = 0.0f;
ftex = _featureTex + idx;
htex = _histoPyramidTex + hist_level_num - 1 - i;
if(GlobalUtil::_timingL) t1= CLOCK();
///
glActiveTexture(GL_TEXTURE0);
tex->BindTex();
htex->AttachToFBO(0);
int tight = ((htex->GetImgWidth() * 2 == tex->GetImgWidth() -1 || tex->GetTexWidth() == tex->GetImgWidth()) &&
(htex->GetImgHeight() *2 == tex->GetImgHeight()-1 || tex->GetTexHeight() == tex->GetImgHeight()));
ShaderMan::UseShaderGenListInit(tex->GetImgWidth(), tex->GetImgHeight(), tight);
htex->FitTexViewPort();
//this uses the fact that no feature is on the edge.
htex->DrawQuadReduction();
//reduction..
htex--;
//this part might have problems on several GPUS
//because the output of one pass is the input of the next pass
//need to call glFinish to make it right
//but too much glFinish makes it slow
for(int k = 0; k <hist_level_num - i - 1 - hist_skip_gpu; k++, htex--)
{
htex->AttachToFBO(0);
htex->FitTexViewPort();
(htex+1)->BindTex();
ShaderMan::UseShaderGenListHisto();
htex->DrawQuadReduction();
}
//glFinish();
//
if(GlobalUtil::_timingL) t2= CLOCK();
//
if(hist_skip_gpu == 0)
{
//read back one pixel
float fn[4];
glReadPixels(0, 0, 1, 1, GL_RGBA , GL_FLOAT, fn);
fcount = (fn[0] + fn[1] + fn[2] + fn[3]);
if(fcount < 1) fcount = 0;
_levelFeatureNum[ idx] = (int)(fcount);
SetLevelFeatureNum(idx, (int)fcount);
//save number of features
ocount+=int(fcount);
_featureNum += int(fcount);
//
if(fcount < 1.0)
{
ot1 += (t2 - t1);
if(GlobalUtil::_timingL) std::cout<<"0\t";
continue;
}
///generate the feature texture
htex= _histoPyramidTex;
htex->BindTex();
//first pass
ftex->AttachToFBO(0);
if(GlobalUtil::_MaxOrientation>1)
{
//this is very important...
ftex->FitRealTexViewPort();
glClear(GL_COLOR_BUFFER_BIT);
glFinish();
}else
{
ftex->FitTexViewPort();
}
ShaderMan::UseShaderGenListStart((float)ftex->GetImgWidth(), htex->GetTexID());
ftex->DrawQuad();
//make sure it finishes before the next step
ftex->DetachFBO(0);
//pass on each pyramid level
htex++;
}else
{
int tw = htex[1].GetDrawWidth(), th = htex[1].GetDrawHeight();
int fc = 0;
glReadPixels(0, 0, tw, th, GL_RGBA , GL_FLOAT, _histo_buffer);
_keypoint_buffer.resize(0);
for(int y = 0, pos = 0; y < th; y++)
{
for(int x= 0; x < tw; x++)
{
for(int c = 0; c < 4; c++, pos++)
{
int ss = (int) _histo_buffer[pos];
if(ss == 0) continue;
float ft[4] = {2 * x + (c%2? 1.5f: 0.5f), 2 * y + (c>=2? 1.5f: 0.5f), 0, 1 };
for(int t = 0; t < ss; t++)
{
ft[2] = (float) t;
_keypoint_buffer.insert(_keypoint_buffer.end(), ft, ft+4);
}
fc += (int)ss;
}
}
}
_levelFeatureNum[ idx] = fc;
SetLevelFeatureNum(idx, fc);
if(fc == 0)
{
ot1 += (t2 - t1);
if(GlobalUtil::_timingL) std::cout<<"0\t";
continue;
}
//////
fcount = (float) fc;
ocount += fc; _featureNum += fc;
/////////////////////
ftex->AttachToFBO(0);
if(GlobalUtil::_MaxOrientation>1)
{
ftex->FitRealTexViewPort();
glClear(GL_COLOR_BUFFER_BIT);
}else
{
ftex->FitTexViewPort();
}
_keypoint_buffer.resize(ftex->GetDrawWidth() * ftex->GetDrawHeight()*4, 0);
///////////
glActiveTexture(GL_TEXTURE0);
ftex->BindTex();
glTexSubImage2D(GlobalUtil::_texTarget, 0, 0, 0, ftex->GetDrawWidth(),
ftex->GetDrawHeight(), GL_RGBA, GL_FLOAT, &_keypoint_buffer[0]);
htex += 2;
}
for(int lev = 1 + hist_skip_gpu; lev < hist_level_num - i; lev++, htex++)
{
glActiveTexture(GL_TEXTURE0);
ftex->BindTex();
ftex->AttachToFBO(0);
glActiveTexture(GL_TEXTURE1);
htex->BindTex();
ShaderMan::UseShaderGenListStep(ftex->GetTexID(), htex->GetTexID());
ftex->DrawQuad();
ftex->DetachFBO(0);
}
if(GlobalUtil::_timingL)
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?