目标:学习Shi-Tomasi角检测, cv.goodFeaturesToTrack()函数。
理论:
在前面的文章学习过Harris角检测,到1994年时J. Shi和C. Tomasi对这个角检测算法进行了改进,发表了论文《Good Features to Track》,
在论文里说明使用两个特征值中较小的一个大于最小阈值,公式如下:
用这个公式替代Harris角公式:
相当于下图的区域寻找:
在这里找到最小的lambda1和lambda2值,并且让它大于lambda最小值,就是绿色区或。可以用下面算法来计算:
1)计窗口里X轴和Y轴的导数。
2)计算lambda1和lambda2,并取最小值保存起来。
3)根据角的质量水平判断。
4)对角按lambda排序
5)对排序结果计算两个角点之间的最短欧式距离。
用下面例子来演示:
#python 3.7.4,opencv4.1
#蔡军生 https://blog.csdn.net/caimouse/article/details/51749579
#
import numpy as np
import cv2
from matplotlib import pyplot as plt
from scipy import signal as sig
def gradient_x(imggray):
##Sobel算子求导
kernel_x = np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]],np.float)
return sig.convolve2d(imggray, kernel_x, mode='same')
def gradient_y(imggray):
kernel_y = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]],np.float)
return sig.convolve2d(imggray, kernel_y, mode='same')
def distance(p1, p2): #欧式距离
y, x = p1
v, u = p2
return ((y - v) ** 2 + (x - u) ** 2) ** 0.5
#读取文件
img = cv2.imread('corner1.png',0)
newImg = img.copy() #拷贝文件
color_img = cv2.cvtColor(newImg, cv2.COLOR_GRAY2RGB) #转换为彩色图片,以便标记红色
window_size = 6 #窗口大小
k = 0.04 #K常数
qualityLevel = 0.01 #角点的质量水平
maxCorners = 25 #想要检测到的角点数目。
minDistance = 10 #两个角点之间的最短欧式距离。
I_x = gradient_x(img)#
I_y = gradient_y(img)#
Ixx = I_x**2
Ixy = I_y*I_x
Iyy = I_y**2
offset = window_size//2
height = img.shape[0]
width = img.shape[1]
#
scored_image_gradient = np.zeros((height,width), np.float32)
for y in range(offset, height-offset):
for x in range(offset, width-offset):
Sxx = np.sum(Ixx[y-offset:y+1+offset, x-offset:x+1+offset])
Syy = np.sum(Iyy[y-offset:y+1+offset, x-offset:x+1+offset])
Sxy = np.sum(Ixy[y-offset:y+1+offset, x-offset:x+1+offset])
#查找角点,min(lambda1, lambda2)
scored_image_gradient[y,x] = min(Sxx, Syy)
#角点的质量水平
good_corners = []
for y in range(height):
for x in range(width):
if scored_image_gradient.item(y,x) >= qualityLevel:
good_corners.append((y,x))
#排序
good_corners.sort(key=lambda k:-scored_image_gradient[k])
top_corners = [good_corners.pop(0)]
for c in good_corners:
distance_curr = lambda corner: distance(c, corner)
if max(map(distance_curr, top_corners)) >= minDistance:
top_corners.append(c)
y, x = c
color_img.itemset((y, x, 0), 0)
color_img.itemset((y, x, 1), 0)
color_img.itemset((y, x, 2), 255)
if len(top_corners) == maxCorners:
break
#显示图片
cv2.imshow('img',img)
cv2.imshow('color_img',color_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果输出如下:
在OpenCV里使用下面的函数:
其中参数:
image:输入图像,一般是灰度图像。
maxCorners: 想要检测到的角点数目。
qualtyLevel: 角点的质量水平,0-1之间。它代表了角点的最低质量,实际用于过滤角点的最小特征值是qualtyLevel与图像中最大特征值的乘积,所以qualtyLevel的值不应超过1(常用的值为0.1或0.01)。低于这个值的所有角点都会被忽略。
minDistance: 两个角点之间的最短欧式距离。
mask: 是一幅像素值为布尔类型的像素,用于指定输入图像中蚕吐角点计算的像素点。
blockSize:计算导数的自相关矩阵时指定点的领域,默认为3,采用小窗口计算的结果比单点(也就是blockSize为1)计算的效果要好。
useHarrisDetector: 默认值为0,若非0,则函数使用Harris的角点定义
K: 当useHarrisDetector非0,则K为用于设置hessian自相关矩阵即对hessian行列式的相对权值的权值系数。
corners:返回(x,y)的序列
演示例子如下:
#python 3.7.4,opencv4.1
#蔡军生 https://blog.csdn.net/caimouse/article/details/51749579
#
import numpy as np
import cv2
from matplotlib import pyplot as plt
#读取文件
img = cv2.imread('corner1.png',0)
newImg = img.copy() #拷贝文件
color_img = cv2.cvtColor(newImg, cv2.COLOR_GRAY2RGB) #转换为彩色图片,以便标记红色
corners = cv2.goodFeaturesToTrack(img,25,0.01,10) #找到25个角
corners = np.int0(corners) #转换为索引数组类型返回,np.int0等于np.intp
for i in corners: #遍历角进行标记
x,y = i.ravel()
cv2.circle(color_img,(x,y),3,255,-1)
#显示图片
cv2.imshow('img',img)
cv2.imshow('color_img',color_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果输出如下:
https://blog.csdn.net/caimouse/article/details/51749579