前言
在计算机视觉领域,图像拼接是一项非常经典且实用的技术,广泛应用于全景图生成、航拍图像拼接、监控画面融合等场景。
本文将基于Python+OpenCV ,使用SIFT 特征点检测 + 暴力匹配 + 单应性矩阵 + 透视变换,从零实现两张图片的自动拼接融合,最终生成一张完整的全景图。
实现原理
- SIFT 特征检测:提取两张待拼接图像的稳定特征点与描述子
- 特征点匹配:使用暴力匹配器匹配两张图像的特征点,过滤错误匹配
- 单应性矩阵计算:通过 RANSAC 算法剔除异常值,计算图像间的变换矩阵
- 透视变换与拼接:对图像进行透视变换,将两张图无缝拼接
完整代码
python
import cv2
import numpy as np
import sys
def cv_show(name, img):
"""显示图像函数"""
cv2.imshow(name, img)
cv2.waitKey(0)
def detectAndDescribe(image):
"""
检测图像SIFT特征点并计算描述符
:param image: 输入图像
:return: 特征点、特征点坐标、描述符
"""
# 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 创建SIFT检测器
sift = cv2.SIFT_create()
# 检测特征点+计算描述子
(kps, des) = sift.detectAndCompute(gray, None)
# 转换关键点坐标为numpy数组
kps_float = np.float32([kp.pt for kp in kps])
return (kps, kps_float, des)
# ===================== 1. 读取待拼接图像 =====================
imageA = cv2.imread("A.jpg")
imageB = cv2.imread("B.jpg")
cv_show('imageA', imageA)
cv_show('imageB', imageB)
# ===================== 2. 提取SIFT特征 =====================
(kpsA, kps_floatA, desA) = detectAndDescribe(imageA)
(kpsB, kps_floatB, desB) = detectAndDescribe(imageB)
# ===================== 3. 特征点匹配与筛选 =====================
# 暴力匹配器
matcher = cv2.BFMatcher()
# KNN匹配(k=2,取最优和次优匹配)
rawMatches = matcher.knnMatch(desB, desA, k=2)
good = []
matches = []
# Lowe比值法过滤错误匹配
for m in rawMatches:
if len(m) == 2 and m[0].distance < 0.65 * m[1].distance:
good.append(m)
matches.append((m[0].queryIdx, m[0].trainIdx))
print(f"有效匹配点数量:{len(good)}")
# 绘制匹配结果
vis = cv2.drawMatchesKnn(imageB, kpsB, imageA, kpsA, good,
outImg=None,
flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv_show("Keypoint Matches", vis)
# ===================== 4. 计算单应性矩阵 =====================
if len(matches) > 4:
# 获取匹配点坐标
ptsB = np.float32([kps_floatB[i] for (i, _) in matches])
ptsA = np.float32([kps_floatA[i] for (_, i) in matches])
# RANSAC算法计算单应性矩阵,剔除异常点
(H, mask) = cv2.findHomography(ptsB, ptsA, cv2.RANSAC, ransacReprojThreshold=10)
else:
print('未找到足够的匹配点!')
sys.exit()
# ===================== 5. 透视变换与图像拼接 =====================
# 构造输出画布尺寸(宽度为两张图之和,高度取原图高度)
result = cv2.warpPerspective(imageB, H, dsize=(imageB.shape[1] + imageA.shape[1], imageB.shape[0]))
# 将图像A粘贴到结果图左侧
result[0:imageA.shape[0], 0:imageA.shape[1]] = imageA
# 显示最终结果
cv_show('result', result)
cv2.imwrite('拼接结果图.jpg', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码逐段解析
1. 图像显示工具函数
python
def cv_show(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
OpenCV 图像显示逻辑,简化代码调用。
2. SIFT 特征检测与描述子计算
python
def detectAndDescribe(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
sift = cv2.SIFT_create()
(kps, des) = sift.detectAndCompute(gray, None)
kps_float = np.float32([kp.pt for kp in kps])
return (kps, kps_float, des)
- 灰度化:降低计算量
- SIFT_create ():创建 SIFT 特征检测器
- detectAndCompute ():同时检测特征点 + 计算 128 维
- 坐标转换:将特征点对象转为坐标数组,方便后续计算
3. 特征点匹配与优化
python
rawMatches = matcher.knnMatch(desB, desA, k=2)
for m in rawMatches:
if len(m) == 2 and m[0].distance < 0.65 * m[1].distance:
good.append(m)
- KNN 匹配:取每个特征点的前两个最优匹配
- Lowe 比值法:剔除错误匹配,阈值 0.65 为经验值,效果最优
4. 单应性矩阵计算
python
(H, mask) = cv2.findHomography(ptsB, ptsA, cv2.RANSAC, 10)
- 单应性矩阵 H:描述两张图像之间的投影变换关系
- RANSAC 算法:自动剔除异常匹配点,提升矩阵精度
- 阈值 10:允许的重投影误差,越大容错越高
5. 透视变换与拼接
python
result = cv2.warpPerspective(imageB, H, (宽, 高))
result[0:高, 0:宽] = imageA
- warpPerspective:对图像 B 进行透视变换,对齐到图像 A
- 直接赋值拼接:将图像 A 覆盖到结果图左侧,完成拼接
运行效果展示
-
输入图像 准备两张有重叠区域的图像 A.jpg、B.jpg


-
特征匹配可视化 程序会自动绘制匹配的特征点,可直观查看匹配效果

-
最终拼接结果 运行后生成
拼接结果图.jpg,两张图像完美拼接成一张全景图
