基于Forstner算法的特征点检测---(详细)

前言


一、Forstner算法是什么?

Forstner 算子是从影像中提取点特征的一种较为有效的算子。其特点是速度快、精度较高。

基本思想:

                  ①.对于角点,对最佳窗口内通过每个像元的边缘直线( 垂直于梯度方向) 进行加权中心化,得到角点的定位坐标;

                   ②.对于圆状点,对最佳窗口内通过每个像元的梯度直线进行加权中心化,得到圆心的坐标。

二.Fortner效果

Fortner算法检测角点效果

Fortner算法检测角点效果

三、算法实现步骤

1.计算各像素的Robort梯度---是为了后面计算窗口内的点协方差矩阵

 其中 g 是灰度函数,g(i,j)表示图像中位置为(i,j)的灰度值大小,g(i,j) ∈ [0,255]

代码如下(示例):

//Step1.1 扩充边界
	Mat img_broaden;
	int top = 0;
	int bottom = 1;
	int left = 0;
	int right = 1;

	copyMakeBorder(img, img_broaden, top, bottom, left, right, BORDER_REFLECT);

	//Step1.2求Robert梯度
	Mat robertX, robertY;
	robertX = Mat::zeros(img.size(), CV_32F);
	robertY = Mat::zeros(img.size(), CV_32F);
	int width = img.size().width;
	int height = img.size().height;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			//gu(i,j) = g(i+1,j+1) - g(i  ,j)
			//gv(i,j) = g(i  ,j+1) - g(i+1,j)
			//gu = float(img_broaden.at<uchar>(i + 1, j + 1) - img_broaden.at<uchar>(i    , j))
			//gv = float(img_broaden.at<uchar>(i    , j + 1) - img_broaden.at<uchar>(i + 1, j))
			robertX.at<float>(i, j) = float(img_broaden.at<uchar>(i + 1, j + 1) - img_broaden.at<uchar>(i    , j));
			robertY.at<float>(i, j) = float(img_broaden.at<uchar>(i    , j + 1) - img_broaden.at<uchar>(i + 1, j));
		
		}
	}

2.求每个窗口的协方差矩阵并计算

 其中 gu 与 gv 是Robert梯度算子,前面已经求得,∑为求和符号,∑gu表达是在窗口内的所有值之和。

代码如下(示例):

//窗口尺寸3*3
int blockW = 3; 
int blockH = 3;
//Step1.3求特征矩阵
for (int i = (blockH - 1)/2; i < height - (blockH - 1)/2; i++) 
	{
		for (int j = (blockW - 1)/2; j < width - (blockW - 1)/2; j++)  
		{
			for (int y = -(blockH - 1)/2; y <= (blockH - 1)/2; y++)
			{
				for (int x = -(blockW - 1)/2; x <= (blockW - 1)/2; x++)
				{
					float gu = robertX.at<float>(i + y, j + x); 
					float gv = robertY.at<float>(i + y, j + x);
					//pow(x,y) = x^y
					sum_guu += pow(gu, 2);//Σgu^2
					sum_gvv += pow(gv, 2);//Σgv^2
					sum_guv += (gu * gv); //Σgugv
				}
			}
		}
	}

3.由协方差矩阵计算权值与圆度

 其中 w 称特征点的权值,q 称为特征点的圆度 ;

代码如下(示例):

//求协方差矩阵的行列式与迹
double detN, trN;
detN = sum_guu * sum_gvv - sum_guv * sum_guv;
trN = sum_guu + sum_gvv;
//求特征点的权值与圆度
double W, R;
W = detN / trN;
R = 4 * detN / (trN * trN);

4.确定待选点并在窗口取极值点为最后的特征点

 

这是其他博文容易落掉的解析

 

       然后以权值为依据, 在窗口中的选取极值点为特征点,即选取窗口中权值最大者为特征点。

代码如下(示例):

for (int i = (blockH - 1) / 2; i < height - (blockH - 1) / 2; i++)// i + blockH - 1 < height
	{
		for (int j = (blockW - 1) / 2; j < width - (blockW - 1) / 2; j++) // j + blockW - 1 < width
		{
			for (int y = -(blockH - 1) / 2; y < (blockH - 1) / 2; y++)
			{
				for (int x = -(blockW - 1) / 2; x < (blockW - 1) / 2; x++)
				{
					if (Matri_W.at<float>(i + y, j + x) > Tw)//权值满足条件时
					{
						if (max_W < Matri_W.at<float>(i + y, j + x))
						{
							max_W = Matri_W.at<float>(i + y, j + x);
							posY = i + y;
							posX = j + x;
						}
					}
				}
			}
			corners.push_back(Point(posX,posY));
		}
	}

四.关注 + 私信可分享完整工程

总结

以上是Fortners算法的基本实现,其运算量比较大,并不实用,所以,笔者已经为此完善,减少计算量,想要工程可以关注与私信可分享工程。

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉默羔羊_GUET

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值