继上一篇文章,代码解读来了
代码还是来自这篇博客
复制过来好了,解读在里边的注释上,不单拎出来一条条解释了,不方便对应
import cv2
import numpy as np
img1 = cv2.imread(r'C:\Users\Bai\Desktop\p2.jpg')
img2 = cv2.imread(r'C:\Users\Bai\Desktop\p1.jpg')
# img1 = cv2.resize(img1, (640, 480))
# img2 = cv2.resize(img2, (640, 480))
input = np.hstack((img1, img2))
cv2.imwrite(r'C:\Users\Bai\Desktop\p2p1.jpg',input)
cv2.imshow('input', input)
cv2.waitKey(0)
def get_homo(img1, img2):
# 1实现实例化图片,就是为对象开辟内存空间
sift = cv2.xfeatures2d.SIFT_create()
# 2实现计算出图像的关键点和sift特征向量,所以关键点是k,特征向量是p1
k1, p1 = sift.detectAndCompute(img1, None)
k2, p2 = sift.detectAndCompute(img2, None)
# 3实现建立匹配关系
bf = cv2.BFMatcher()
# 4实现返回两个DMatch类型,是两个与原图像特征点最接近的两个特征点,
# 这两个特征点的欧氏距离小于一定值才会匹配成功,所以这个2就是那个一定值?
matches = bf.knnMatch(p1, p2, k=2)
# 5实现昂,当m1的距离小于0.8倍m2时,被过滤为有效特征点,都添加到good后面
good = []
for m1, m2 in matches:
if m1.distance < 0.8 * m2.distance:
good.append(m1)
# 6实现单应性矩阵计算,单应性矩阵就是尺度因子*内参*外参,
#最后算出来的就是物体在世界坐标系和像素坐标系之间的位置映射关系
#findHomography计算多个二维点对之间的最优单映射变换矩阵H
if len(good) > 8:
img1_pts = []
img2_pts = []
for m in good:
img1_pts.append(k1[m.queryIdx].pt)
img2_pts.append(k2[m.trainIdx].pt)
img1_pts = np.float32(img1_pts).reshape(-1, 1, 2)
img2_pts = np.float32(img2_pts).reshape(-1, 1, 2)
H, mask = cv2.findHomography(img1_pts, img2_pts, cv2.RANSAC, 5.0)
return H
else:
print('piints is not enough 8!')
exit()
def stitch_img(img1, img2, H):
# 1实现获得图像的四个角点坐标,对的,就是用高和宽,也就是图片的形状shape,
#shape的三个参数为(高,宽,通道数),高和宽对应着行数和列数,通道数一般为3,RGB嘛因为
#shape[:2]就是前两个参数的意思
h1, w1 = img1.shape[:2]
h2, w2 = img2.shape[:2]
img1_point = np.float32([[0,0], [0,h1], [w1,h1], [w1,0]]).reshape(-1, 1, 2)
img2_point = np.float32([[0,0], [0,h2], [w2,h2], [w2,0]]).reshape(-1, 1, 2)
# 2实现根据单映射变换矩阵H对img1_point进行变换,是对图1的变换
img1_trans = cv2.perspectiveTransform(img1_point, H)
# 将img1变换后的角点与img2原来的角点做拼接
result_point = np.concatenate((img2_point, img1_trans), axis=0)
# 获得拼接后图像x,y的最小值
[x_min, y_min] = np.int32(result_point.min(axis=0).ravel()-0.5)
# 获得拼接后图像x,y的最大值
[x_max, y_max] = np.int32(result_point.max(axis=0).ravel()+0.5)
# 平移距离
trans_dist = [-x_min, -y_min]
# 构建一个齐次平移矩阵
trans_array = np.array([[1, 0, trans_dist[0]],
[0, 1, trans_dist[1]],
[0, 0, 1]])
# 这里是我新加的输出,第一个是输出单应性平移变换矩阵HT,也就是单映射变换矩阵H+齐次平移矩阵T,
# 第二个是输出单映射变换矩阵
# 第三个输出齐次平移矩阵
# 第四个输出HT的行列式
# 第五个输出H的行列式
# 注:这里的输出仅为个人研究需要
print(trans_array.dot(H))
print(H)
print(trans_array)
print(np.linalg.det(trans_array.dot(H)))
print(np.linalg.det(H))
# 平移和单应性变换函数cv2.warpPerspective
#对1图进行平移和单应性变换(输入的图像,输出的图像(可略),透视变换的单应性平移矩阵H,输出图像的大小)
#所以上面获取拼接后图像的最大最小值就是为了确定拼接后的图片的尺寸!
res_img = cv2.warpPerspective(img1, trans_array.dot(H), (x_max-x_min, y_max-y_min))
# 3实现把图2覆盖在图1上,所以如果颠倒图片顺序,生成的结果也会不一样
res_img[trans_dist[1]:trans_dist[1]+h2,
trans_dist[0]:trans_dist[0]+w2] = img2
return res_img
H = get_homo(img1, img2)
res_img = stitch_img(img1, img2, H)
# 4实现 显示拼接结果,保存拼接结果
cv2.imshow('result', res_img)
cv2.imwrite(r'C:\Users\Bai\Desktop\p2-p1.jpg',res_img)
cv2.waitKey(0)
我什么时候才能像有些大佬一样用英文写学习笔记啊……感觉就只有我在给代码加一行一行又一行的中文白话文,罢了罢了
总之这个代码可以直接复制到spyder运行,还是两部分,第一张图片连接的结果显示出来之后任意键开始图片拼接,如果是用手机拍的那种大分辨率照片(比如我的竖屏尺寸是3120x4160),就会有点点慢,单纯想粗略看看运行效果的话就把开头resize那两行的注释取消掉,resize成你想要的大小,就会运行的快点了,记得修改图片路径、连接和拼接的路径哦!