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 + -
显示快捷键?