Harris角点检测的实现(cv::Mat && c++)

本文详细介绍了Harris角点检测算法的工作原理,包括如何通过计算R值判断像素点是否为角点、边缘点或光滑区域。文章还提供了具体的代码实现,展示了如何计算dx和dy,以及如何应用非极大值抑制避免角点过度密集。

原文链接或Google “A COMBINED CORNER AND EDGE DETECTOR”可以找到Harris角点检测的论文。

简单的概括一下,Harris角点检测的原理为,通过计算论文中的R来判断某一个像素点是否为角点,通常情况下,当R为正数且较大时,该点为角点。若R为负数且绝对值较大时,该点为边缘点。若R的绝对值较小,则该点通常位于光滑区域。

计算R需要两个基本量,一个为dx,另一个为dy,通常情况下,我们会计算像素点所在的窗口内(我的代码中采用了2*2的区域)所有像素点的梯度,然后进行第二步的计算。在代码中,x方向的梯度为dx[4],y方向的梯度为dy[4]。

得到梯度后,我们需要计算论文中的A,B,C

A=\sum \left ( dx^{2} \right )

B=\sum \left ( dy^{2} \right )

C=\sum \left ( dx*dy \right )

至此我们将得到论文中的M=$$\left[ \begin{matrix} A & C \\ C & B \end{matrix}\right] \tag{1} $$

下面我们将计算R,根据线性代数的基本公式,我们可以得到

R=A*B-C^{2}-k(A+B)^{2},其中,k的取值通常为0.04~0.06(k越小,Harris算子越敏感)。得到R之后,我们便可以找到角点。然后通过非极大值抑制(Non-maximal Suppression)的方法,避免角点过于密集的出现。

代码为Harris角点响应值计算

double Harris(const cv::Mat& image, int x, int y) {
	int A, B, C;
	int dx[4];
	// 0 1
	// 2 3
	dx[0] = (int)image.at<uchar>(y, x + 1) - image.at<uchar>(y, x - 1);
	dx[1] = (int)image.at<uchar>(y, x + 2) - image.at<uchar>(y, x);
	dx[2] = (int)image.at<uchar>(y + 1, x + 1) - image.at<uchar>(y + 1, x - 1);
	dx[3] = (int)image.at<uchar>(y + 1, x + 2) - image.at<uchar>(y + 1, x);

	int dy[4];
	dy[0] = (int)image.at<uchar>(y + 1, x) - image.at<uchar>(y - 1, x);
	dy[1] = (int)image.at<uchar>(y + 1, x + 1) - image.at<uchar>(y - 1, x + 1);
	dy[2] = (int)image.at<uchar>(y + 2, x) - image.at<uchar>(y, x);
	dy[3] = (int)image.at<uchar>(y + 2, x + 1) - image.at<uchar>(y, x + 1);

	A = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2] + dx[3] * dx[3];
	B = dy[0] * dy[0] + dy[1] * dy[1] + dy[2] * dy[2] + dy[3] * dy[3];
	C = dx[0] * dy[0] + dx[1] * dy[1] + dx[2] * dy[2] + dx[3] * dy[3];

	return A * B - C * C -0.04 * (A + B) * (A + B);
}

非极大值抑制的可以采用只保留某一个窗口内Harris响应值最大的点进行处理,在此不贴代码了。

注:万不可偷懒只求一个点的dx和dy,否则得到的值恒为负数,因为A*B-C^{2}=0

import cv2 as cv import numpy as np """"" cv2.cornerHarris() 可以用来进行检测。参数如下: • img - 数据类型为 float32 的输入图像。 • blockSize - 检测中要考虑的领域大小。 • ksize - Sobel 求导中使用的窗口大小 • k - Harris 检测方程中的自由参数,取值参数为 [0,04,0.06] """"" src_inital = cv.imread("E:/opencv/picture/building.jpg") src = cv.cvtColor(src_inital,cv.COLOR_BGR2GRAY) src = np.float32(src) dst = cv.cornerHarris(src,3,3,0.04) #R值是由det(M)-K(trace(M))*(trace(M)),当该时,该所对应的R值就会很大,通过设置对R的阈值,就可以筛选得到 #这里的dst就是R值构成的灰度图像,灰度图像坐标会与原图像对应,R值就是分数,当R值很大的时候 就可以认为这个是一个 print(dst.shape) src_inital[dst>0.08*dst.max()]=[0,0,255] """"" src_inital[dst>0.08*dst.max()]=[0,0,255] 这句话来分析一下 dst>0.08*dst.max()这么多返回是满足条件的dst索引值,根据索引值来设置这个的颜色 这里是设定一个阈值 当大于这个阈值分数的都可以判定为 dst其实就是一个个度分数R组成的,当λ1和λ2都很大,R 也很大,(λ1和λ2中的最小值都大于阈值)说明这个区域是。 那么这里为什么要大于0.08×dst.max()呢 注意了这里R是一个很大的值,我们选取里面最大的R,然后只要dst里面的值大于百分之八的R的最大值  那么此时这个dst的R值也是很大的 可以判定他为,也不一定要0.08可以根据图像自己选取不过如果太小的话 可能会多圈出几个不同的 """"" cv.imshow("inital_window",src_inital) cv.waitKey(0) cv.destroyAllWindows() 目标: 理解Harris检测的概念 使用函数cv2.cornerHarris(),cv2.cornerSubPix() 原理: Harris 检测的方法大概原理就是建立一个窗口区域,然后以当前窗口为中心向各个方向进行偏移。 如上图所示,第一个窗口向各个方向偏移的时候,像素值没有变化,因为窗口偏移的时候没有遇到任何边缘信息。 第二个图,窗口当中有一个直线(即block是在边缘上),如果当前窗口进行上下的移动,也没有像素值发生变化(在其他方向上灰度值也会变化)。 第三个图,窗口覆盖了一个“拐”,如果窗口进行偏移,任何方向上都会有像素变化。 所以,第三张图片判断为检测。 判断特征是否为的依据:R只与M值有关,R为大数值正数时特征,R为大数值负数时为边缘,R为小数值时为平坦区 寻找R位于一定阈值之上的局部最大值,去除伪。 方向导数IxIx和IyIy可以使用cv2.Sobel()函数得到 Harris检测的结果是灰度图,图中的值为检测的打分值。需要选取合适的阈值对结果进行二值化来检测
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值