opencv在进行模板匹配时需要算子进行特征提取,算子可以是SIFT,SURF,ORB,Harris,FAST等。
将结果绘制到原图分为一下步骤:
1.特征提取,建立特征点,并计算特征描述子。
def find_keypoints(image):
sift = cv2.SIFT_create(): # 初始化sift
(keypoints, features) = sift.detectAndCompute(image, None) # 计算图片的特征点,以及描述子
# type(kps) = <class 'tuple'>
# type(kps[0]) = <class 'cv2.KeyPoint'>
keypoints= np.float32([keypoint.pt for keypoint in keypoints]) 将特征点转化为数组
return (keypoints, feature)
2.使用暴力匹配器匹配检测出来的关键点,并用KNN和warpPerspective求出转换角度。
def warpper_affine(image_1, image_2):
keypoints_1, features_1 = find_keypoints(image1)
keypoints_2, features_2 = find_keypoints(image2)
bf = cv2.BFMatcher()
matches = bf.knnMatch(features_1 , features_2 , 2)
# match匹配的返回结果是DMatch类型。
# DMatch数据结构包含三个非常重要的数据分别是queryIdx,trainIdx,dist
# queryIdx:某一特征点在本帧图像的索引;
# trainIdx:trainIdx是该特征点在另一张图像中相匹配的特征点的索引;
# distance:代表这一对匹配的特征点描述符的欧式距离,数值越小也就说明俩个特征点越相近。
is_matchs = []
for matche in matches:
# 当最近距离跟次近距离的比值小于ratio值时,保留此匹配对
if len(matche) == 2 and matche[0].distance < matche[1].distanc * 0.75:
# 存储两个点在featuresA, featuresB中的索引值
is_matchs.append((matche[0].trainIdx, matche[0].queryIdx))
if len(is_matchs) > 4:
# 获取匹配对的点坐标
ptsA = np.float32([keypoints_1[i] for (_, i) in is_matchs])
ptsB = np.float32([keypoints_2[i] for (i, _) in is_matchs])
# 计算视角变换矩阵
M, status = cv2.findHomography(ptsA, ptsB, cv2.RANSAC,4.0) #计算的是B到A的变换矩阵
return M
3.根据变换矩阵将模板,绘制到目标图上;
def plot_edge(image_1, M, image_2):
"""
Args:
image_1: 输入的模板图片
H: 变换矩阵
image_2: 要绘制的作为底片的图片
Returns:
"""
# 计算变换后的图片
image_1 = cv2.warpPerspective(image_1, M, (image_2.shape[0], image_2.shape[1]))
# 绘制灰度图
gray = cv2.cvtColor(image_1, cv.COLOR_BGR2GRAY)
# canny边缘检测
edge = cv2.Canny(gray, 100, 250, 3)
# 提取边缘位置
(thresh, blackEdges) = cv2.threshold(edge, 0, 255, cv2.THRESH_BINARY_INV)
# 将边缘位置绘制到目标图片上
image_2[blackEdges == 0] = (0, 0, 255)
return image_2
4.完整代码下:
import cv2 as cv
import cv2
import numpy as np
def plot_edge(image_1, H, image_2):
"""
Args:
image_1: 输入的模板图片
H: 变换矩阵
image_2: 相机采集的图片
Returns:
"""
image_1 = cv.warpPerspective(image_1, H, (image_2.shape[0], image_2.shape[1]))
gray = cv.cvtColor(image_1, cv.COLOR_BGR2GRAY)
edge = cv.Canny(gray, 100, 250, 3)
(thresh, blackEdges) = cv.threshold(edge, 0, 255, cv.THRESH_BINARY_INV)
image_2[blackEdges == 0] = (0, 0, 255)
return image_2
def warpper_affine(image_1, image_2):
keypoints_1, features_1 = find_keypoints(image_1)
keypoints_2, features_2 = find_keypoints(image_2)
bf = cv2.BFMatcher()
matches = bf.knnMatch(features_1 , features_2 , 2)
# match匹配的返回结果是DMatch类型。
# DMatch数据结构包含三个非常重要的数据分别是queryIdx,trainIdx,dist
# queryIdx:某一特征点在本帧图像的索引;
# trainIdx:trainIdx是该特征点在另一张图像中相匹配的特征点的索引;
# distance:代表这一对匹配的特征点描述符的欧式距离,数值越小也就说明俩个特征点越相近。
is_matchs = []
for matche in matches:
# 当最近距离跟次近距离的比值小于ratio值时,保留此匹配对
if len(matche) == 2 and matche[0].distance < matche[1].distance * 0.75:
# 存储两个点在featuresA, featuresB中的索引值
is_matchs.append((matche[0].trainIdx, matche[0].queryIdx))
if len(is_matchs) > 4:
# 获取匹配对的点坐标
ptsA = np.float32([keypoints_1[i] for (_, i) in is_matchs])
ptsB = np.float32([keypoints_2[i] for (i, _) in is_matchs])
# 计算视角变换矩阵
M, status = cv.findHomography(ptsA, ptsB, cv.RANSAC,4.0) #计算的是B到A的变换矩阵
return M
def find_keypoints(image):
sift = cv.SIFT_create() # 初始化sift
(keypoints, features) = sift.detectAndCompute(image, None) # 计算图片的特征点,以及描述子
# type(kps) = <class 'tuple'>
# type(kps[0]) = <class 'cv2.KeyPoint'>
keypoints= np.float32([keypoint.pt for keypoint in keypoints]) #将特征点转化为数组
return (keypoints, features)
if __name__ == '__main__':
image = cv2.imread("E:/test_image/detect_image.jpeg")
image_1 = cv2.imread("E:/test_image/rotate_image.jpeg")
M = warpper_affine(image, image_1)
image_2 = plot_edge(image, M , image_1)
cv.imshow("image", image)
cv.imshow("image_1", image_1)
cv.imshow("plot_edge", image_2)
cv2.waitKey(0)
测试图片:
测试结果: