新版的OPENCV中SIFT特征被剔除了,需要安装老版本的opencv(如3.4.15.55等)
代码来源CSDN博客
和原版其区别:将作为匹配样本的船只切片放到’SAMPLE’文件夹内,进行检测模式时,会自动和文件夹内所有船只图片进行匹配。
# 注:sift必须在3.4.15下运行,后面的有专利
import numpy as np
import cv2
from matplotlib import pyplot as plt
import os
def sift_dect(path1,path2,MIN_MATCH_COUNT = 4):
img1 = cv2.imread(path1, 1)
img2 = cv2.imread(path2, 1)
exx = 0.8
exy = 0.8
img1 = cv2.resize(img1, dsize=None, fx=exx, fy=exy)
img2 = cv2.resize(img2, dsize=None, fx=exx, fy=exy)
# 使用SIFT检测角点,创建角点检测器
sift = cv2.xfeatures2d.SIFT_create()
# 获取关键点和描述符
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
# 定义FLANN匹配器------KD树,具体原理尚不清楚,index_params中的algorithm为0或1
index_params = dict(algorithm=1, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
# 使用KNN算法匹配,FLANN里边就包含的KNN、KD树还有其他的最近邻算法
matches = flann.knnMatch(des1, des2, k=2)
# print(matches)
# 去除错误匹配
good = []
for m, n in matches: #m为第一邻近,n为第二邻近,两者距离满足以下关系才认为是正确匹配
if m.distance <= 0.7 * n.distance:
good.append(m)
# good保存的是正确的匹配
# 单应性
if len(good) > MIN_MATCH_COUNT:
# 改变数组的表现形式,不改变数据内容,数据内容是每个关键点的坐标位置
src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
# findHomography 函数是计算变换矩阵
# 参数cv2.RANSAC是使用RANSAC算法寻找一个最佳单应性矩阵H,即返回值M
# 返回值:M 为变换矩阵,mask是掩模
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
if M is None: return None
# ravel方法将数据降维处理,最后并转换成列表格式
matchesMask = mask.ravel().tolist()
# 获取img1的图像尺寸
h, w, dim = img1.shape
# pts是图像img1的四个顶点
pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)
# 计算变换后的四个顶点坐标位置
dst = cv2.perspectiveTransform(pts, M)
# 根据四个顶点坐标位置在img2图像画出变换后的边框
img2 = cv2.polylines(img2, [np.int32(dst)], True, (0, 0, 255), 1, cv2.LINE_AA)
return img2
else:
matchesMask = None
return None
if __name__ == '__main__':
flag = 'all'
if flag == 'all':
folder = 'SAMPLE'
names = os.listdir(folder)
path2s = ['000619.jpg','001159.jpg','Sen_ship_hh_0201610150202806.jpg']
for path2 in path2s:
for name in names:
path1 = os.path.join(folder,name)
img = sift_dect(path1,path2)
if img is not None:
new_name = os.path.join('result',path2[:-4]+'_'+name[:-4]+'.jpg')
print(new_name)
cv2.imwrite(new_name,img)
else:
path1 = '..\dataset\VOCdevkit_SarShipDataset\VOC2007\JPEGImages\Gao_ship_hh_020160825440109064.jpg'
path2 = '000619.jpg'
img = sift_dect(path1,path2)