角点检测
原理:
特性:向任何方向移动变化都很大
Harris 角点检测
将窗口向各个方向移动(u,v)然后计算所有差异的总和,窗口函数可以是正常的矩形窗口也可以是对每一个像素给予不同权重的高斯窗口。
角点检测中要使E (u; v) 的值最大。这就是说必须使方程右侧的第二项的取值最大。
详情参考:https://docs.opencv.org/master/dc/d0d/tutorial_py_features_harris.html
所以Harris 角点检测的结果是一个由角点分数构成的灰度图像
选取适当的阈值对结果图像进行二值化我们就检测到了图像中的角点。我们将用一个简单的图片来演示一下。
Open 中的函数cv2.cornerHarris(src, blockSize, ksize, k[, dst[, borderType]]) → dst 可以用来进行角点检测。参数如下:
Parameters:
src – Input single-channel 8-bit or floating-point image.
dst – Image to store the Harris detector responses. It has the typeCV_32FC1 and the same size assrc .
blockSize – Neighborhood size (see the details oncornerEigenValsAndVecs() ).
ksize – Aperture parameter for theSobel() operator.
k – Harris detector free parameter. See the formula below.
borderType – Pixel extrapolation method. SeeborderInterpolate() .
* img - 数据类型为float32 的输入图像。
* blockSize - 角点检测中要考虑的领域大小。
* ksize - Sobel 求导中使用的窗口大小
* k - Harris 角点检测方程中的*参数,取值参数为[0,04,0.06].
代码示例:
"""
#!/usr/bin/env python
# -*- coding:utf-8 -*-
@desc:特征提取和描述
"""
import cv2
import numpy as np
from matplotlib import pyplot as plt
# Harris角点检测
def harris_detection(file_path):
file_name = file_path
img = cv2.imread(file_name)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
# 输入像素必须是float32, 最后一个参数在0.04到0.05之间
dst = cv2.cornerHarris(gray, 2,3,0.04)
# 用于标记角点
dst = cv2.dilate(dst, None)
# 一个最优的阈值,依赖于图片的变量
img[dst > 0.01*dst.max()] = [0,0,255]
cv2.imshow('dst', img)
if cv2.waitKey(0) & 0xff == 27:
cv2.destroyAllWindows()
# 亚像素级精确度的Harris角点检测
def sub_pix_corner_dectetion(file_path):
file_name = file_path
img = cv2.imread(file_name)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 获取角点
gray = np.float32(gray)
# 输入像素必须是float32, 最后一个参数在0.04到0.05之间
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
dst = cv2.dilate(dst, None)
ret, dst = cv2.threshold(dst, 0.01*dst.max(), 255, 0)
dst = np.uint8(dst)
# 找到质心
ret, labels, stats, centroids = cv2.connectedComponentsWithStats(dst)
# 定义停止迭代的标准,并重新定义角点
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001)
# 返回值由角点坐标组成的一个数组(而非图像)
corners = cv2.cornerSubPix(gray, np.float32(centroids), (5, 5), (-1, -1), criteria)
# 画出角点
res = np.hstack((centroids, corners))
# np.int0 可以用来省略小数点后面的数字(非四五入)。
res = np.int0(res)
img[res[:, 1], res[:, 0]] = [0, 0, 255]
img[res[:, 3], res[:, 2]] = [0, 255, 0]
cv2.imwrite(r'D:\workplace\data\opencv\subpixel5.png', img)
# 改进
# Shi-Tomasi 角点检测&&适合于跟踪的图像特征
def shi_tomasi_detection(file_path):
img = cv2.imread(file_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(gray,25,0.01, 10)
#
corners = np.int0(corners)
for i in corners:
x, y = i.ravel()
cv2.circle(img, (x, y), 3, (0, 255, 0), -1)
plt.imshow(img)
plt.show()
if __name__ == '__main__':
# file_path = r"D:\workplace\data\opencv\OIP-C.jfif"
# harris_detection(file_path)
# sub_pix_corner_dectetion(file_path)
file_path1 = r"D:\workplace\data\opencv\20161113111710572.png"
shi_tomasi_detection(file_path1)