之前想用TensorFlow + OpenCV做目标检测,但是最后因为TF2.0资料属实不多所以夭折了,不过OpenCV还是非常值得学习的。
特征检测算法
OpenCV中比较常用的特征检测和提取算法:
- Harris:用于角点检测
- SIFT:用于斑点检测
- SERF:用于斑点检测
- FAST:用于角点检测
- BRIEF:用于斑点检测
- ORB:带方向的FAST算法和具有旋转不变性的BRIEF算法(暴力匹配和基于FLANN的匹配法)
特征
上述算法中提到了角点和斑点,这是两种重要的特征。特征是有意义的图像区域。
cornerHarris角点特征
Harris算法中认为,平坦区域在所有方向上都没有明显的梯度变化,边缘区域在某个方向上有明显的梯度变化,角度边缘则在各个方向都有明显的梯度变化。
下面用一张国际象棋的图片和cornerHarris演示角点识别
import cv2
import numpy as np
img = cv2.imread('chess.jpg')
gray1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#灰化,可以降低维度,将三通道变为一通道
gray = np.float32(gray1)
dst = cv2.cornerHarris(gray, 2, 15, 0.04)
#参数依次为:输入图像,角点区域大小,求导使用的窗口大小,自由参数取值[0.04, 0.06]
#其中第二个参数决定检测到的角点的大小,第三个参数决定检测的灵敏度,越小越灵敏,但必须是[3, 31]之间的奇数
img[dst>0.01*dst.max()] = [0, 0, 255]#给角点上色方便观察
while(True):
cv2.imshow('pre', gray1)
cv2.imshow('result', img)
if cv2.waitKey(1) & 0xff == ord('q'):
break
cv2.destroyAllWindows()
结果:
调节灵敏度可以得到效果更好的图像,cornerharris的检测效果与图像比例有关,图像越小越可能丢失角点
Shi-Tomas角点检测
Shi-Tomas是对Harris的改进算法
import cv2
import numpy as np
img = cv2.imread("chess.jpg")
print(img.shape)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(gray, 100, 0.05, 10)
for pt in corners:
x = np.int32(pt[0][0])
y = np.int32(pt[0][1])
cv2.circle(img, (x,y), 5, (0, 0, 255), 2)
cv2.imshow('result', img)
while(True):
if cv2.waitKey(1) & 0xff == ord('q'):
break
cv2.destroyAllWindows()
cv2.goodFeaturesToTrack 参数:
- 单通道输入图像
- 最多返回的角点数量
- 灵敏度,越低失去的点越多
- 相邻角点间的最短距离
基于ORB的特征检测和特征匹配
ORB将FAST关键点和基于BRIEF描述符的技术相结合,有更快的检测速度
FAST
FAST算法会在像素周围绘制一个圆,包含16个像素。然后将每个像素与加上一个阈值的圆心像素进行比较,若有连续、比加上阈值的圆心像素更亮或暗的像素,则可认为圆心是角点的。
BRIEF
BRIEF不是特征检测算法,而是描述符。角点检测算法计算的结果实际上分为两部分,一个是角点的坐标,另一个是整幅图的特征(可以看成数的累积)而特征在OpenCV里称为描述符。
暴力匹配
暴力匹配是一种基本没有优化的特征匹配方法
代码实现
import numpy as np
import cv2
import matplotlib.pyplot as plt
img1 = cv2.imread('football.jpg', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('shoot.jpg', cv2.IMREAD_GRAYSCALE)
orb = cv2.ORB_create() #创建检测器
kp1, des1 = orb.detectAndCompute(img1, None) #计算特征值
kp2, des2 = orb.detectAndCompute(img2, None)
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) #匹配特征值
matches = bf.match(des1, des2) #遍历描述符,计算匹配质量(距离)
matches = sorted(matches, key=lambda x:x.distance) #排序
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:40], img2, flags=2) #显示匹配质量最高的前40个点
plt.imshow(img3)
plt.show()
效果: