RANSAC+SIFT影像特征匹配(python-opencv)

文章讲述了使用OpenCV中的SIFT特征检测和BFMatcher进行图像匹配,然后通过粗筛和RANSAC算法进行精确匹配,以减少误匹配的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先读入图片

import cv2
import numpy as np

img1=cv2.imread("./picture1/picture1/1/14x00424.JPG")
img2=cv2.imread("./picture1/picture1/1/14x00425.JPG")

然后识别影像特征点及其特征点描述子

sift = cv2.SIFT_create(1000)

kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

构建匹配器,执行KNN匹配。

bf=cv2.BFMatcher()

matches = bf.knnMatch(des1,des2,k=2)
"""
这里有个大坑,当你想这里直接画出所有的匹配时,
这里面的matches返回的是最近距离和次近距离的两个Dmacther元组。
如下图,直接用drawMatches函数时,matches1 to matches2就会是含有两个值的元组,然后出现BUG。
"""

但是在后续粗匹配时,我们又需要最近邻次距离之比做粗匹配筛选错点。如果不需要,建议直接用matches直接做暴力匹配。

但是

实现多幅影像拼接的步骤如下: 1. 读取所有待拼接的影像并转换为灰度图像; 2. 使用 SIFT 算法提取关键和描述子; 3. 使用 FLANN 或 BFMatcher 算法匹配关键; 4. 根据匹配得到的对计算单应性矩阵; 5. 使用单应性矩阵将影像拼接起来。 下面是基于 Python-OpenCV 实现多幅影像拼接的示例代码: ```python import cv2 import numpy as np # 读取待拼接的影像 img1 = cv2.imread('image1.png') img2 = cv2.imread('image2.png') img3 = cv2.imread('image3.png') # 转换为灰度图像 gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) gray3 = cv2.cvtColor(img3, cv2.COLOR_BGR2GRAY) # 创建 SIFT 对象 sift = cv2.xfeatures2d.SIFT_create() # 提取关键和描述子 kp1, des1 = sift.detectAndCompute(gray1, None) kp2, des2 = sift.detectAndCompute(gray2, None) kp3, des3 = sift.detectAndCompute(gray3, None) # 创建 FLANN 匹配器 FLANN_INDEX_KDTREE = 0 index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) search_params = dict(checks=50) flann = cv2.FlannBasedMatcher(index_params, search_params) # 匹配关键 matches1_2 = flann.knnMatch(des1, des2, k=2) matches2_3 = flann.knnMatch(des2, des3, k=2) # 根据 Lowe's ratio test 筛选匹配 good_matches1_2 = [] for m, n in matches1_2: if m.distance < 0.7 * n.distance: good_matches1_2.append(m) good_matches2_3 = [] for m, n in matches2_3: if m.distance < 0.7 * n.distance: good_matches2_3.append(m) # 提取匹配对的坐标 src_pts1_2 = np.float32([kp1[m.queryIdx].pt for m in good_matches1_2]).reshape(-1, 1, 2) dst_pts1_2 = np.float32([kp2[m.trainIdx].pt for m in good_matches1_2]).reshape(-1, 1, 2) src_pts2_3 = np.float32([kp2[m.queryIdx].pt for m in good_matches2_3]).reshape(-1, 1, 2) dst_pts2_3 = np.float32([kp3[m.trainIdx].pt for m in good_matches2_3]).reshape(-1, 1, 2) # 计算单应性矩阵 H1_2, _ = cv2.findHomography(src_pts1_2, dst_pts1_2, cv2.RANSAC, 5.0) H2_3, _ = cv2.findHomography(src_pts2_3, dst_pts2_3, cv2.RANSAC, 5.0) # 拼接影像 h1, w1 = img1.shape[:2] h2, w2 = img2.shape[:2] h3, w3 = img3.shape[:2] # 计算拼接后的影像大小 max_w = max(w1 + w2, w2 + w3) max_h = max(h1, h2, h3) # 创建空白影像 result = np.zeros((max_h, max_w, 3), dtype=np.uint8) # 将第一幅影像拼接到空白影像上 result[:h1, :w1] = img1 # 将第二幅影像拼接到空白影像上 tmp_img = cv2.warpPerspective(img2, H1_2, (max_w, max_h)) result[:h2, w1:w1+w2] = tmp_img[:, w1:w1+w2] # 将第三幅影像拼接到空白影像上 tmp_img = cv2.warpPerspective(img3, H1_2.dot(H2_3), (max_w, max_h)) result[:h3, w1+w2:max_w] = tmp_img[:, w2:w3] # 显示拼接后的影像 cv2.imshow('result', result) cv2.waitKey() cv2.destroyAllWindows() ``` 注意,这里使用了 Lowe's ratio test 进行匹配筛选,并使用 RANSAC 算法计算单应性矩阵。实际应用中,根据不同的场景和数据,可能需要调整这些参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值