Surf算子匹配

本文详细介绍了如何通过构建影像金字塔来提高SURF算子的提取效率,包括影像金字塔的构建、匹配数据尺寸设定、数据正规化、积分影像计算以及SURF算子的匹配与优化步骤。重点突出了金字塔影像在SURF算子提取过程中的应用,以及如何通过调整参数实现匹配点的精确匹配。
/**
* @brief 计算获得金字塔影像的surf算子
* @param strImg 影像路径
* @param surfPnts surf算子容器
* @param iMaxSearchSize 金字塔影像宽高的最大阈值
* @param dblThres surf阈值
* @param Surf匹配使用的影像金字塔层号
* SURF算法计算过程缓慢,读取金字塔影像计算,读取金字塔的层数根据
* iMaxSearchSize确定
*/
bool OnExtarctPyramidSurfPnt(string strImg, vector<Ipoint> &surfPnts,
							 int iMaxSearchSize, double dblThres, 
							 int &iLevel)

OpenSURF基于OpenCV开发,使用该开源代码,需要同时下载OpenCV和OpenSURF

(1)影像建立金字塔

遥感影像通常尺寸较大,直接利用OpenSURF提取Surf算子运算速度较慢(利用OpenSurf的源代码直接做大图像的匹配根本是不可能的,速度太慢),因此需要基于金字塔影像进行提取

使用GDAL创建金字塔

/**
 * @brief 构建影像金字塔
 */
bool COMRasterDataset::BuildPyramid()
{
	long lWidth, lHeight;
	if (!GetSize(lWidth, lHeight))
	{
		return false;
	}

	int iLevelCount = 0;
	long lMinSize = lWidth<lHeight?lWidth:lHeight;
	while (lMinSize > iMaxLevelPyramidSize)
	{
		lMinSize /= 2;
		iLevelCount++;
	}
	int *iOverviewLists = new int[iLevelCount];
	for (int i=0; i<iLevelCount; i++)
	{
		iOverviewLists[i] = pow(2.0, i+1);
	}
	if (mpDataset->BuildOverviews("GAUSS", iLevelCount, iOverviewLists,
		0, NULL, GDALDummyProgress, NULL) != CE_None)
	{
		delete []iOverviewLists;
		return false;
	}

	delete []iOverviewLists;

	return true;
}

(2)设置匹配数据的尺寸的最大值iMaxSearchSize(如1024),确定读取金字塔的第几层。(在GDAL中pBand->GetOverview(iLevel),iLevel=0获取的并不是原始数据层)

iLevel = -1;
long lWidth, lHeight;
if (!pRasterDataset->GetSize(lWidth, lHeight))
{
	return false;
}
long lMinSize = lWidth<lHeight?lWidth:lHeight;
while (lMinSize>iMaxSearchSize)
{
	iLevel++;
	lMinSize /= 2;
	lWidth /= 2;
	lHeight /= 2;
}

(3)读取金字塔层的影像数据,并进行正规化(将数据规则化到0-1之间)
对于多波段影像的彩色数据,最好能够按照一定的比例合并为一个波段进行计算,例如pPanBand = 0.2*pBand1 + 0.5*pBand2 + 0.3*pBand3;
读取金字塔层的数据:

GDALRasterBand *pBand = 
		(GDALRasterBand*)mpDataset->GetRasterBand(iBand+1);
if (!pBand)
{
	return false;
}
GDALRasterBand *pOverviewBand = 
	pBand->GetOverview(iLevel);
if (!pOverviewBand)
{
	return false;
}

CPLErr err = pOverviewBand->RasterIO(GF_Read, iStartCol, iStartRow,
	iWidth, iHeight, pBuffer, iWidth, iHeight,
	pOverviewBand->GetRasterDataType(), 0, 0);
if (err != CE_None)
{
	return false;
}

将数据进行归一化,以unsigned char型为例:
for (int i=0; i<iHeight; i++)
{
	for (int j=0; j<iWidth; j++)
	{
		pDest[i*iWidth+j] = float(pSrc[i*iWidth+j]/255.0);
	}
}

(4)OpenSURF中计算用到的是积分影像,对获取的正规化数据进行积分计算


m,n位置的像素值等于所有横坐标小于等于m,纵坐标小于等n的值

if (!pSrc)
{
	return false;
}

float fTemp = 0;
for (int i=0; i<iWidth; i++)
{
	fTemp += pSrc[i];
	pIntergral[i] = fTemp;
}

for (int j=1; j<iHeight; j++)
{
	fTemp = 0;
	for (int i=0; i<iWidth; i++)
	{
		fTemp += pSrc[j*iWidth+i];
		pIntergral[j*iWidth+i] = pIntergral[(j-1)*iWidth+i] + fTemp;
	}
}
return true;

(5)改写OpenSURF的源代码

OpenSURF中的参数都是OpenCV的影像参数,如果想使用可以有两种方法:第一,需要将数据构造成为OpenCV的影像;第二,改造OpenSURF的代码,传递数据指针

//! Library function builds vector of described interest points
inline void surfDetDes(IplImage *img,  /* image to find Ipoints in */
                       std::vector<Ipoint> &ipts, /* reference to vector of Ipoints */
                       bool upright = false, /* run in rotation invariant mode? */
                       int octaves = OCTAVES, /* number of octaves to calculate */
                       int intervals = INTERVALS, /* number of intervals per octave */
                       int init_sample = INIT_SAMPLE, /* initial sampling step */
                       float thres = THRES /* blob response threshold */)

修改第一个参数IplImage *img为float *pImageBuffer

 

(6)在对原始影像以及参考影像进行SURF算子提取后,对两张影像的算子点进行匹配

//! Populate IpPairVec with matched ipts 
void getMatches(IpVec &ipts1, IpVec &ipts2, IpPairVec &matches)

(7)剔除粗差点,计算两张影像的仿射变换关系

放大显示:



因为是基于金字塔影像进行匹配,因此匹配点的坐标会存在一定的误差,计算得到的仿射变换关系也仅仅是两张相片的粗略位置关系。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值