传知代码-一键找出图像中物体的角点(论文复现)
代码以及视频讲解
本文所涉及所有资源均在传知代码平台可获取
概述
本文复现论文A COMBINED CORNER AND EDGE DETECTOR中提出的图像中的物体角点检测算法,也称Harris算法。原文连接https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=88cdfbeb78058e0eb2613e79d1818c567f0920e2
该论文所提出的角点检测算法是计算机视觉领域的经典算法,至今仍在计算机视觉领域有着广泛的应用。
该方法对算力几乎没有任何要求,依据图像邻域内灰度值的分布特点来对图像中各区域的角点进行判断。不像深度学习需要依靠大量数据的训练且对数据集分布有依赖性,所以时至今日依然在工业界有着很高的应用价值。
算法原理
正如边缘在灰度图像中在某一个方向上会出现明显的灰度变化,角点在图像中往往是在两个方向上都出现明显的灰度变化。
如在此图中,红点标注处的角点在两个箭头方向的垂直方向上都有明显的灰度变化,两个红色箭头标注出了它的两个灰度变换边缘。
假设我们现在要检测的图片为 I I I,在图像处理中,能够充分体现图像灰度变化特征的是它的方向导数, I x I_{x} Ix与 I y I_{y} Iy,分别代表图像 I I I的水平方向导数与竖直方向导数。
I x ( i , j ) = I ( i , j + 1 ) − I ( i , j − 1 ) 2 I_{x}(i, j)=\frac{I(i, j+1)-I(i, j-1)}{2} Ix(i,j)=2I(i,j+1)−I(i,j−1)
I y ( i , j ) = I ( i − 1 , j ) − I ( i + 1 , j ) 2 I_{y}(i, j)=\frac{I(i-1, j)-I(i+1, j)}{2} Iy(i,j)=2I(i−1,j)−I(i+1,j)
Harris算法就是利用图像的方向导数制定了一个响应指标:
R = d e t ( M ) − k ⋅ t r a c e ( M ) 2 R=det(M)-k\cdot trace(M)^2 R=det(M)−k⋅trace(M)2
个人感觉原文的公式不太好理解,以下我将按照我的理解对公式进行适当的改变。
对于R,实际上是一个R图,其尺寸与我们要检测的图像 I I I一致,于是上面的相应指标实际上是每个像素都有一个相应指标,即:
R ( i , j ) = d e t ( M ( i , j ) ) − k ⋅ t r a c e ( M ( i , j ) ) 2 R(i,j)=det(M(i,j))-k\cdot trace(M(i,j))^2 R(i,j)=det(M(i,j))−k⋅trace(M(i,j))2
其中
M ( i , j ) = [ A ( i , j ) B ( i , j ) B ( i , j ) C ( i , j ) ] M(i,j)=\left[\begin{array}{ll} A(i,j) & B(i,j) \\ B(i,j) & C(i,j) \end{array}\right] M(i,j)=[A(i,j)B(i,j)B(i,j)C(i,j)]
在用3X3邻域内的数据进行操作时,A(i,j)、B(i,j)、C(i,j)在原文中对应的定义应该是这样的:
A ( i , j ) = ∑ m = − 1 1 ∑ n = − 1 1 ω ( m , n ) I x 2 ( i + m , j + n ) B ( i , j ) = ∑ m = − 1 1 ∑ n = − 1 1 ω ( m , n ) I x ( i + m , j + n ) × I y ( i + m , j + n ) C ( i , j ) = ∑ m = − 1 1 ∑ n = − 1 1 ω ( m , n ) I y 2 ( i + m , j + n ) A(i, j)=\sum_{m=-1}^{1} \sum_{n=-1}^{1} \omega (m,n)I_{x}^{2}(i+m, j+n) \\ B(i, j)=\sum_{m=-1}^{1} \sum_{n=-1}^{1} \omega (m,n)I_{x}(i+m, j+n) \times I_{y}(i+m, j+n) \\ C(i, j)=\sum_{m=-1}^{1} \sum_{n=-1}^{1} \omega (m,n)I_{y}^{2}(i+m, j+n) A(i,j)=m=−1∑1n=−1∑1ω(m,n)Ix2(i+m,j+n)B(i,j)=m=−1∑1n=−1∑1ω(m,n)Ix(i+m,j+n)×Iy(i+m,j+n)C(i,j)=m=−1∑1n=−1∑1ω(m,n)Iy2(i+m,j+n)
即对 I x 2 I_x^2 Ix2、 I y 2 I_y^2 Iy2和 I x I y I_xI_y IxIy三个方向导数图在3X3邻域内进行卷积得到A、B和C。
其中 ω \omega ω是高斯平滑核,主要是为了减少噪声对方向导数的影响。大多数情况下, ω \omega ω取一个全一矩阵就好。本方法也是采用了全一矩阵,所以以上定义可以修改为:
A ( i , j ) = ∑ m = − 1 1 ∑ n = − 1 1 I x 2 ( i + m , j + n ) B ( i , j ) = ∑ m = − 1 1 ∑ n = − 1 1 I x ( i + m , j + n ) × I y ( i + m , j + n ) C ( i , j ) = ∑ m = − 1 1 ∑ n = − 1 1 I y 2 ( i + m , j + n ) A(i, j)=\sum_{m=-1}^{1} \sum_{n=-1}^{1} I_{x}^{2}(i+m, j+n) \\ B(i, j)=\sum_{m=-1}^{1} \sum_{n=-1}^{1} I_{x}(i+m, j+n) \times I_{y}(i+m, j+n) \\ C(i, j)=\sum_{m=-1}^{1} \sum_{n=-1}^{1} I_{y}^{2}(i+m, j+n) A(i,j)=m=−1∑1n=−1∑1Ix2(i+m,j+n)B(i,j)=m=−1∑1n=−1∑1Ix(i+m,j+n)×Iy(i+m,j+n)C(i,j)=m=−1∑1n=−1∑1Iy2(i+m,j+n)
所以 R R R指标的最终定义可以改为:
R ( i , j ) = Det ( M ( i , j ) ) − k ( Tr ( M ( i , j ) ) ) 2 = ( A ( i , j ) C ( i , j ) − B ( i , j ) 2 ) − k × ( A ( i , j ) + C ( i , j ) ) 2 R(i,j)=\operatorname{Det}(M(i,j))-k(\operatorname{Tr}(M(i,j)))^{2}=\left(A(i,j) C(i,j)-B(i,j)^{2}\right)-k \times(A(i,j)+C(i,j))^{2} R(i,j)=Det(M(i,j))−k(Tr(M(i,j)))2=(A(i,j)C(i,j)−B(i,j)2)−k×(A(i,j)+C(i,j))2
其中k是一个经验参数,本算法中取0.02,当然也可以根据具体情况进行调整,通常来说k越大,算法对角点的判别就越严格,会有更少的点被判别为角点;k越小,算法的判别就越松一些,会有更多的点被判别为角点。
得到R图后,将R图中最大值 R m a x R_max Rmax的0.2倍作为阈值。将R图中小于 0.2 R m a x 0.2R_max 0.2Rmax的像素坐标判别为是角点坐标,其余的则为非角点坐标,最终得到我们的结果图。
演示效果
核心逻辑
def HarrisCornerDetector(image,k=0.02):
# 读取图像# 将图像转换为numpy数组I= imageI=np.array(I)sobel_x = np.array([[0, 0, 0], [-0.5, 0, 0.5], [0, 0, 0]])sobel_y=np.array([[0,0.5,0],[0,0,0],[0,-0.5,0]])# 对图像进行水平方向的卷积I_x = convolve2d(I, sobel_x, mode="same", boundary="symm")I_y=convolve2d(I,sobel_y,mode='same',boundary='symm')I2_x=I_x**2I2_y=I_y**2Ix_Iy=I_x*I_ysobel=np.array([[1,1,1],[1,1,1],[1,1,1]])A=convolve2d(I2_x,sobel,mode="same",boundary="symm")B=convolve2d(Ix_Iy,sobel,mode="same",boundary="symm")C=convolve2d(I2_y,sobel,mode="same",boundary="symm")R=(A*C-B**2)-k*(A+C)**2R_max=np.max(R[1:-1,1:-1])C=RC[C<=(0.2*R_max)]=0C[C>(0.2*R_max)]=1return C
使用方式
基础镜像
python:3.9.7
配置环境
解压后进入HarrisCornerDetector项目路径下
运行以下命令:
pip install -r requirements.txt
直接运行
python main.py
即可看到视频中示例图片的角点检测效果。
更换图片运行
修改main.py文件里的默认图片路径
将"data/rice.png"更改为你自己的图片路径即可。
同时,我也找了第二张示例图片放在了data路径下,将"data/rice.png"更换为"data/1.webp",就可以看到演示图片中棋盘的角点检测效果。
参考文献
[1] Harris C, Stephens M. A combined corner and edge detector[C]//Alvey vision conference. 1988, 15(50): 10-5244.
源码下载