前言
无
一、Forstner算法是什么?
Forstner 算子是从影像中提取点特征的一种较为有效的算子。其特点是速度快、精度较高。
基本思想:
①.对于角点,对最佳窗口内通过每个像元的边缘直线( 垂直于梯度方向) 进行加权中心化,得到角点的定位坐标;
②.对于圆状点,对最佳窗口内通过每个像元的梯度直线进行加权中心化,得到圆心的坐标。
二.Fortner效果
![](https://img-blog.csdnimg.cn/3b0586d9486d4a38aeaa68c61d2f41cf.png)
![](https://img-blog.csdnimg.cn/1aa15cdbb83b419abf3298d9f7ba70b2.png)
三、算法实现步骤
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.确定待选点并在窗口取极值点为最后的特征点
![](https://img-blog.csdnimg.cn/34f5e4f8ac9044d2a77bd72e90b75d87.png)
然后以权值为依据, 在窗口中的选取极值点为特征点,即选取窗口中权值最大者为特征点。
代码如下(示例):
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算法的基本实现,其运算量比较大,并不实用,所以,笔者已经为此完善,减少计算量,想要工程可以关注与私信可分享工程。