Harris角点检测python实现及基于opencv实现

写在前面:

黄宁然, 七月,骄阳似火。

参考文献镇楼:

[1]袁志聪,基于harris特征的点云配准方法研究
[2]高亭,基于改进Harris角点检测的印刷体文档图像检索技术
[3]景庆阳,基于harris角点检测的KCF算法研究.
[4]zoukankan,OpenCV计算机视觉学习(13)——图像特征点检测(Harris角点检测,sift算法),
[5] Harris角点检测原理【OpenCV教程】
[6] 勿在浮砂筑高台,【特征匹配】Harris及Shi-Tomasi原理及源码解析
注:csdn发文助手提示“外链过多”,故文献链接网址请见评论区。

问题来源:

笔者的执念。

1、原理简介

Harris算法是chris harris等提出的一种基于信号的点特征提取算法,是对Moravec算子的改良和优化[1]。Moravec算子主要是研究图像的固定窗口在四个不同方向上的移动,比较窗口中的像素灰度变化情况的大小,而harris角点检测则是比较窗口在任意方向滑动前后的灰度变化大小的情况,并且用数学表达式确定特征点的位置;同时引入了平滑因子,进一步增强了抗干扰能力[2]。若窗口移动前后,灰度发生了较大变化,则判断窗口中存在角点,否则窗口内不存在角点[1]。根据文献[3],具体公式推导如下。
当窗口的偏移量为[j,q]时,滑动前后窗口的灰度变化为:
在这里插入图片描述

式中,Window(x,y)是用来滤波的高斯函数,I(x+j,y+q)为移动后的图像灰度,I(x,y)为原始图像灰度。
根据泰勒公式,二次展开为:
在这里插入图片描述
则式(1)变换为:
在这里插入图片描述

其中,Ix、Iy分别为x、y方向上的偏导数
可将式(4)简写成:
在这里插入图片描述
其中
在这里插入图片描述
矩阵M也可以进一步写成:
在这里插入图片描述
其中,A、B、C分别是 I x 2 I_x^2 Ix2 I y 2 I_y^2 Iy2 I x y I_xy Ixy 在窗口w内的求和,即:
在这里插入图片描述
上述就得到自相关函数的表达式。据文献4,这是一椭圆的矩阵表达形式(非标准椭圆),所以系数矩阵M的特征值与椭圆的半轴长短有关。而椭圆的半轴长短也影响到曲率,也即M的特征值会影响到自相关函数的变化快慢。如何影响?可看文献4的讲解(笔者数学不好,这里也是一知半解)。
根据文献4,对于一标准椭圆,其表达式为:
在这里插入图片描述
矩阵形式为:
在这里插入图片描述
则系数矩阵:
在这里插入图片描述
则特征值与半轴的关系为:
在这里插入图片描述
结论是:特征值大,半轴短。
在这里插入图片描述
便得到边界、平面、角点几种情况下,特征值的大小情况:
(1)边界。一个特征值大,另一个特征值小,λ1 >> λ2 或者 λ2 >> λ1。自相关函数值在某一个方向上大,在其他方向上小。
(2)平面。两个特征值都小,且近似相等;自相关函数数值在各个方向上都小。
(3)角点。两个特征值都很大且近似相等,自相关函数在所有方向都增大。
在这里插入图片描述
实际中,Harris算法并不需要计算具体的特征值,而是根据角点响应值R来判断角点[2],R的定义为:
在这里插入图片描述
其中,detM为矩阵M的行列式,traceM为矩阵M的迹,k为Harris算子参数,据文献3,其一般取值为[0.04,0.06]。据文献5,角点响应值判断角点的依据如下:
在这里插入图片描述
即:
(1)当R为大数值的正数时是角点
(2)当R为大数值的负数时是边界
(3)当R为小数是认为是平坦区域
综上,Harris 算法分以下几个步骤[2]:
(1)计算图像在水平方向和垂直方向的导数 I x Ix Ix I y Iy Iy 以及 I x 2 I_x^2 Ix2 I y 2 I_y^2 Iy2 I x y I_xy Ixy
(2)根据式(8)对上述元素进行平滑滤波,以得到系数 A、B、C,得到M。
(3)将求得的系数带入式(13)~式(15),来计算角点响应值 R。
(4)对于各响应值R,若大于设定好的阈值,则该R对应的坐标即为角点。

2、python源码实现

参阅文献6,基于python自行编写代码实现harris角点检测。几点需要注意的地方:
(1)通过sobel算子,快速实现图像x、y方向上导数的求取;
(2)opencv在实现harris算子时,窗口函数并非取的高斯函数,而是普通的boxFilter函数(即权值均为1,且求和后,不归一化)。
引用库:

#coding=utf8
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import math
import cv2
import os,sys
import scipy.ndimage
import time
import scipy

harris角点检测代码:

```bash
def harris_corner_detect(img_src,block_size=2,aperture_size=3,k=0.04,borderType=cv2.BORDER_DEFAULT):
	if img_src.dtype!=np.uint8:
		raise ("input image shoud be uint8 type")
	R_arr = np.zeros(img_src.shape,dtype=np.float32)#用来存储角点响应值
	img = img_src.astype(np.float32)
	scale = 1.0/( (aperture_size-1)*2*block_size*255 )#参考opencv实现源码,在sobel算子时乘以这个系数
	#借助sobel算子,计算x、y方向上的偏导数
	Ix = cv2.Sobel(img,-1,dx=1,dy=0,ksize=aperture_size,scale=scale,borderType=borderType)
	Iy = cv2.Sobel(img,-1,dx=0,dy=1,ksize=aperture_size,scale=scale,borderType=borderType)
	Ixx = Ix**2
	Iyy = Iy**2
	Ixy = Ix*Iy
	#借助boxFilter函数,以block_size为窗口大小,对窗口内的数值求和,且不归一化
	f_xx = cv2.boxFilter(Ixx,ddepth=-1,ksize=(block_size,block_size) ,anchor =(-1,-1),normalize=False, borderType=borderType)
	f_yy = cv2.boxFilter(Iyy,ddepth=-1,ksize=(block_size,block_size),anchor =(-1,-1),normalize=False,borderType=borderType)
	f_xy = cv2.boxFilter(Ixy, ddepth=-1,ksize=(block_size,block_size),anchor =(-1,-1),normalize=False,borderType=borderType)
	# 也可以尝试手动求和
	radius = int((block_size - 1) / 2)  # 考虑blocksize为偶数的情况,奇数时,前、后的数量一样;为偶数时,后比前多一个
	N_pre = radius
	N_post = block_size - N_pre - 1
	row_s, col_s = N_pre, N_pre
	row_e, col_e = img.shape[0] - N_post, img.shape[1] - N_post
	#开始计算每一个坐标下的响应值
	for r in range(row_s,row_e):
		for c in range(col_s,col_e):
			#手动对窗口内的数值求和
			#sum_xx = Ixx[r-N_pre:r+N_post+1,c-N_pre:c+N_post+1].sum()
			#sum_yy = Iyy[r-N_pre:r+N_post+1,c-N_pre:c+N_post+1].sum()
			#sum_xy = Ixy[r-N_pre:r+N_post+1,c-N_pre:c+N_post+1].sum()
			#或者直接使用boxFilter的结果
			sum_xx = f_xx[r,c]
			sum_yy = f_yy[r, c]
			sum_xy = f_xy[r, c]
			#根据行列式和迹求响应值
			det = (sum_xx * sum_yy) - (sum_xy ** 2)
			trace = sum_xx + sum_yy
			res = det - k * (trace ** 2)
			# 或者用如下方式求行列式和迹
			#M = np.array([[sum_xx,sum_xy],[sum_xy,sum_yy]])
			#res = np.linalg.det(M) - (k *  (np.trace(M))**2 )
			R_arr[r,c] = res
	return R_arr

主程序调用:
这里,响应值的门限选择为最大响应值得0.01倍。

if __name__ == '__main__':
	img_src = cv2.imread('susan_input1.png',cv2.IMREAD_GRAYSCALE)
	#source code
	res_arr = harris_corner_detect(img_src,block_size=2,aperture_size=3,k=0.04)
	max_v = np.max(res_arr)
	res_arr[res_arr<0.01*max_v]=0
	img_show = img_src.copy()
	if(len(img_show.shape)==2):
		img_show = cv2.cvtColor(img_show,cv2.COLOR_GRAY2BGR)
	img_show[res_arr!=0] = (255,0,0)
	print(len(np.where(res_arr!=0)[0]))
	print(np.max(res_arr))
	plt.figure()
	plt.title("corners-raw")
	plt.imshow(img_show, cmap=cm.gray)
	plt.show()

检测结果如下:
在这里插入图片描述

3、基于opencv实现

Opencv自带harris算子,可以直接求取响应矩阵。这里使用的opencv版本为3.4.2.16
调用方式为:
dst = cv2.cornerHarris(img_src,blockSize= 2,ksize= 3,k= 0.04)
主程序调用:

if __name__ == '__main__':
	img_src = cv2.imread('susan_input1.png',cv2.IMREAD_GRAYSCALE)
	#source code
	res_arr = harris_corner_detect(img_src,block_size=2,aperture_size=3,k=0.04)
	max_v = np.max(res_arr)
	res_arr[res_arr<0.01*max_v]=0
	img_show = img_src.copy()
	if(len(img_show.shape)==2):
		img_show = cv2.cvtColor(img_show,cv2.COLOR_GRAY2BGR)
	img_show[res_arr!=0] = (255,0,0)
	print(len(np.where(res_arr!=0)[0]))
	print(np.max(res_arr))
	plt.figure()
	plt.title("corners-raw")
	plt.imshow(img_show, cmap=cm.gray)
	#opencv库函数调用
	dst = cv2.cornerHarris(img_src,blockSize= 2,ksize= 3,k= 0.04) #blockSize为窗口大小,ksize为sobel算子的核大小,k为harris算子参数
	img_show2 = img_src.copy()
	if (len(img_show2.shape) == 2):
		img_show2 = cv2.cvtColor(img_show2, cv2.COLOR_GRAY2BGR)
	dst2 = dst.copy()
	dst2[dst<= 0.01* dst.max()]=0
	img_show2[dst2!=0] = (255, 0, 0)
	print(len(np.where(dst2 != 0)[0]))
	print(np.max(dst2))
	plt.figure()
	plt.title("opencv")
	plt.imshow(img_show2, cmap=cm.gray)
	plt.show()

opencv库函数检测结果如下:
在这里插入图片描述
将自行编写的harris角点检测代码运行结果与opencv运行结果相对比,二者一致(仅仅比较了数量、最大值)。

4、非极大值抑制

可根据需要,执行非极大值抑制。

非极大值抑制代码:

def corner_nms(corner,kernal=3):
	out = corner.copy()
	row_s = int(kernal/2)
	row_e = out.shape[0] - int(kernal/2)
	col_s,col_e = int(kernal/2),out.shape[1] - int(kernal/2)
	for r in range(row_s,row_e):
		for c in range(col_s,col_e):
			if corner[r,c]==0: #不是可能的角点
				continue
			zone = corner[r-int(kernal/2):r+int(kernal/2)+1,c-int(kernal/2):c+int(kernal/2)+1]
			index = corner[r,c]<zone
			(x,y) = np.where(index==True)
			if len(x)>0 : #说明corner[r,c]不是最大,直接归零将其抑制
				out[r,c] = 0
	return out

在上文基础上,调用nms:

	#nms
	score_nms = corner_nms(res_arr)
	img_show3 = cv2.cvtColor(img_src,cv2.COLOR_GRAY2BGR)
	img_show3[score_nms != 0] = (255, 0, 0)
	plt.figure()
	plt.title("corners-nms")
	plt.imshow(img_show3, cmap=cm.gray)

	plt.show()

经过nms抑制后的结果:
在这里插入图片描述

5、python源码下载

Python程序源码下载地址
https://download.csdn.net/download/xiaohuolong1827/85847444

  • 11
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Harris角点检测是一种常见的计算机视觉算法,它可以检测图像中的角点。在Python中,可以使用OpenCV库来实现Harris角点检测。 下面是一个简单的Harris角点检测Python实现的示例: ``` import cv2 import numpy as np # 加载图像 img = cv2.imread('image.jpg') # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 计算Harris角点 dst = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04) # 通过阈值进行筛选 img[dst > 0.01 * dst.max()] = [0, 0, 255] # 显示结果 cv2.imshow('Harris Corner Detection', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 首先,使用`cv2.imread`函数加载要处理的图像。然后,将图像转换为灰度图像,以便进行角点检测。接下来,使用`cv2.cornerHarris`函数计算图像中的Harris角点。在这个函数中,`blockSize`是要考虑的邻域大小,`ksize`是Sobel算子的大小,`k`是Harris角点响应函数的参数。然后,通过设置一个阈值来筛选角点,并将它们用红色标记出来。最后,使用`cv2.imshow`函数显示结果。 这是一个简单的Harris角点检测Python实现示例,可以根据具体情况进行调整和优化。 ### 回答2: Harris角点检测是一种计算机视觉中常用的角点检测算法,用于识别图像中的角点。Python有很多库可以实现Harris角点检测,这里以OpenCV库为例进行讲解。 首先,我们需要导入OpenCV库: ```python import cv2 ``` 然后,读取图像并将其转换为灰度图像: ```python image = cv2.imread('image.jpg') # 读取图像 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转换为灰度图像 ``` 接下来,通过调用`cv2.cornerHarris()`函数实现Harris角点检测: ```python dst = cv2.cornerHarris(gray, 2, 3, 0.04) # 进行Harris角点检测 ``` 在上述代码中,`gray`是输入的灰度图像,`2`是角点窗口(卷积窗口)的大小,`3`是Sobel算子(用于计算梯度的算子)的孔径尺寸,`0.04`是Harris角点检测的自由参数k。 接下来,使用`cv2.dilate()`函数对角点图像进行膨胀操作,以便更好地显示角点: ```python dst = cv2.dilate(dst, None) # 对角点图像进行膨胀操作 ``` 然后,根据设定的阈值,将角点标记为最大值: ```python image[dst > 0.01 * dst.max()] = [0, 0, 255] # 根据阈值将角点标记为红色 ``` 最后,显示检测结果的图像: ```python cv2.imshow('Harris Corner Detection', image) # 显示检测结果 cv2.waitKey(0) cv2.destroyAllWindows() ``` 以上就是使用Python实现Harris角点检测的步骤。通过对图像进行角点检测,我们可以在图像中找到重要的角点,这对于很多计算机视觉任务(如特征提取、图像配准等)是非常有用的。 ### 回答3: Harris角点检测是一种经典的计算机视觉算法,用于检测图像中的角点。下面是使用Python实现Harris角点检测的步骤: 1. 导入所需的库:首先导入OpenCV和NumPy库,用于图像处理和数组计算。 2. 读取图像:使用OpenCV的imread函数读取待处理的图像。 3. 图像灰度化:将读取的图像转换为灰度图像,可以使用OpenCV的cvtColor函数实现。 4. 计算图像的梯度:使用Sobel算子计算图像在x和y方向的梯度值,可以使用OpenCV的Sobel函数。 5. 计算Harris响应函数:根据Harris角点检测的定义,计算Harris响应函数R。 6. 阈值处理:设置一个阈值,将Harris响应函数大于阈值的像素点作为角点。 7. 绘制角点:根据计算得到的角点位置,在原图像上绘制特殊标记,可以使用OpenCV的circle函数。 8. 显示结果:显示处理结果,可以使用OpenCV的imshow函数。 9. 保存结果:保存处理后的图像,可以使用OpenCV的imwrite函数。 以上就是使用Python实现Harris角点检测的基本步骤。在实际编码中,还可以根据需要进行参数调整和优化,以获得更好的检测结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值