角点特征常常是图像中独特的存在,比如你在玩拼图游戏时,首先肯定会去找一些独一无二的匹配项,比如人像的眼睛,嘴巴,这些特征你很容易判断哪些碎片应该拼凑在一起,而相比之下,那些比较常见的特征你需要最后多次调整才能找到对的位置。角点特征就是这样较独特的存在,下图中矩形的右上角点区域,无论你往哪个方向移动,图像的信息都会发生变化,而边缘则沿某一个方向移动时不会变化,至于矩形内部区域,则无论哪个方向移动,图像信息没有变化[引用自官方教程]。
本文内容涉及以下内容(参考OpenCV3 计算机视觉第6章)
- Harris角点检测
- Shi-Tomasi角点检测(Harris的修改版)
- FAST角点检测
有了特征点,怎么用呢?你可以比对不同图像的特征信息,进行目标检测、图像拼接等。在OpenCV中,可以通过下面的算子来进行特征匹配:
- Brute-Force匹配法,也称暴力匹配法
- 基于FLANN的匹配法
1.使用Harris以及Shi-Tomasi算子获取角点
注:这里采用Shi-Tomasi仅保留最好的12个角点信息(匹配比较好),而harris输出了全部角点,圆圈颜色深表示该处检测到的次数多。
import cv2
import numpy as np
import time
img = cv2.imread('approx_star.png', -1)
img_copy = img.copy()
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gaussian_img = cv2.GaussianBlur(gray_img,(3, 3),0)
# 输入图像必须是float32
float_img = np.float32(gaussian_img)
# Harris角点检测
## src: 输入图像
## blockSize:邻域大小
## ksize:Sobel算子中的核大小
## k :Harris检测参数,经验范围:[0.04, 0.06],值越大,假角点越少,不过可能会漏检
start_time = time.time()
dst = cv2.cornerHarris(float_img, 4, 3, 0.08)
end_time = time.time()
print('Harris Detection used :%s ms.' % ((end_time - start_time) * 1000))
dot_locs = np.where(dst > (0.01 * dst.max()))
for loc in zip(*dot_locs[::-1]):
cv2.circle(img, loc, 5, (25, 25, 255), 1)
# Shi-Tomasi方法检测
## src: 输入图像
## maxCorners:输出的角点数目,可以帮助你找到最佳的maxCorners个角点,会将角点进行排序
## qualityLevel:检测质量水平系数,经验值[0.01, 0.1]
## minDistance:最小的角点距离,小于该距离的角点会被忽视
start_time = time.time()
corners = cv2.goodFeaturesToTrack(gaussian_img, 12, 0.01, 10)
end_time = time.time()
print('goodFeaturesToTrack Detection used :%s ms.' % ((end_time - start_time) * 1000))
corners = np.int64(corners)
for corner in corners:
x, y = corner.flatten()
cv2.circle(img_copy, (x, y), 5, (255, 25, 255), 3)
cv2.imshow('harris_corners', img)
cv2.imshow('shi-tomasi_corners', img_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 耗时情况:
# Harris Detection used :5.984783172607422 ms.
# goodFeaturesToTrack Detection used :9.972572326660156 ms.
补充:
1.关于参数ksize和检测自由设置参数k,可参考博客【cornerHarris中的ksize和k是什么意思】--https://www.jb51.cc/python/533133.html
2.官方角点检测参考链接:https://docs.opencv.org/3.0-beta/modules/imgproc/doc/feature_detection.html?highlight=cv2.cornerharris#cv2.cornerHarris
3.goodFeaturesToTrack 函数参数详解https://blog.csdn.net/guduruyu/article/details/69537083 这个函数可以输入mask信息
4.对于有更精细检测需求的,可以使用cornerSubPix()来检测亚像素角点
对于FAST检测角点的基本使用方法如下:
# 创建检测器,大多数情况下阈值设置较大,太低会造成大量的假特征点
# 选择非极大值抑制会使得特征点会少一些,避免一些假特征点
# type可选择FAST_FEATURE_DETECTOR_TYPE_9_16,在像素周围取16个点,当9个满足条件,就是特征点,除此之外,可选择7_12, 5_8
fast=cv2.FastFeatureDetector_create(threshold = 20, nonmaxSuppression=False,
type=cv2.FAST_FEATURE_DETECTOR_TYPE_9_16)
# 返回的kp为keypoint类,你可以使用kp[0].pt获取第一个特征点的坐标信息
# detect第二个参数为特征点,第三个参数为mask
kp = fast.detect(gray_img, None)
# 耗时情况
# FAST Detection used :0.9963512420654297 ms.
参考博客:
1.OPENCV图像特征点检测与FAST算法https://www.cnblogs.com/dengxiaojun/p/5302778.html讲解该函数的算法及参数
2.KeyPoint类参考博客:https://blog.csdn.net/leonardohaig/article/details/81289648
2.特征点匹配
你可以用特征点用在两幅图的信息比对上,这一点在图像拼接中尤为重要,至于说用特征进行目标检测,比如《OpenCV3 计算机视觉》中有将特征信息作为纹身信息的比对.不过,当你的环境特征信息量比较多(比如风景)的时候,匹配出错的概率非常大.# ORB特征点匹配
import cv2
import numpy as np
import time
# 特征图像
img = cv2.imread('fuji_features1.png',-1)
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 待匹配图像
img1 = cv2.imread('fuji_feature.jpg',-1)
gray_img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
start_time = time.time()
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(gray_img, None)
kp2, des2 = orb.detectAndCompute(gray_img1, None)
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck = True)
matches = bf.match(des1, des2)
end_time = time.time()
print('ORB Detect Features and BFMatch used :%s ms.' % ((end_time - start_time) * 1000))
# good_matches = []
# for m, n in matches:
# if m.distance < 0.75 * n.distance:
# good_matches.append([m])
# 按照特征点距离进行排序,距离越小约好
# 参考博客:https://blog.csdn.net/u013000248/article/details/85325136
matches = sorted(matches, key = lambda x : x.distance)
img2 = cv2.drawMatches(img, kp1, img1, kp2, matches[:40], np.array([]), flags = 2)
cv2.imshow('ORB_corners', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.1 ORB 特征 + FLANN匹配
需要注意一下,ORB 进行特征提取的descriptor格式需要转换下,否则是无法进行FLANN匹配
FLANN_INDEX_KDTREE = 1
indexParams = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
searchParams = dict(check = 50)
flann = cv2.FlannBasedMatcher(indexParams, searchParams)
# 转为np.float32
matches = flann.knnMatch(np.float32(des1), np.float32(des2), k = 2)
相关博客:
角点特征检测之三(FLANN匹配)https://blog.csdn.net/wsp_1138886114/article/details/90578810
关于opencv-python的特征检测及匹配部分相关内容非常多,由于目前暂未涉及相关应用,如果你的应用中涉及相关内容,有问题的话请在评论区留言.Have Fun With OpenCV-Python, 下期见。