GitHub
Image-Stitching
学习源码来自Github-pavanpn/Image-Stitching
主要函数:
1. cv2.cvtColor()
颜色空间转换函数
img_yuv=cv2.cvtColor(img,k) # img是需要转换对图片,k是转换成何种格式
# cv2.COLOR_BGR2RGB 将BGR格式转换成RGB格式
# cv2.COLOR_BGR2GRAY 将BGR格式转换成灰度图片
2. cv2.equalizeHist()
直方图均衡化函数
cv2.equalizeHist(img) # 将要均衡化的原图像[要求是灰度图像]作为参数传入,则返回值即为均衡化后的图像
3. bf=cv2.BFMatcher()、matches=bf.knnMatch()
K-最邻近匹配
# 暴力匹配BFMatcher,遍历描述符,确定描述符是否匹配,然后计算匹配距离并排序
# BFMatcher函数参数:
# normType:NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2。
# NORM_L1和NORM_L2是SIFT和SURF描述符的优先选择
# NORM_HAMMING和NORM_HAMMING2是用于ORB算法
bf = cv2.BFMatcher(normType=cv2.NORM_HAMMING, crossCheck=True)
matches = bf.knnMatch(d1, d2, k=1) #获得knn检测器,d1,d2为描述子
# knn匹配可以返回k个最佳的匹配项,bf返回所有的匹配项
4. cv2.findHomography()
单应矩阵发现函数
M,mask=cv2.findHomography(img1_pts,img2_pts,cv2.RANSAC,5.0)
# img1_pts 目标图像的特征点集合
# 第三个参数 配准方法的选择
# 第四个参数 每次抽取样本的个数,仅RANSAC和RHO有
5. cv2.perspectiveTransform()
透视变换函数
cv2.perspectiveTransform(src, m[, dst]) → dst
# src:输入的2通道或者3通道的图片
# m:变换矩阵
6. np.concatenate()
result_dims=np.concatenate((img1_dims,img2_dims),axis=0)
# 前两个参数为要拼接对数组
# axis参数为指定按照哪个维度进行拼接,axis=0则代表着按照第一维度进行拼接
上述两个数组不能按行拼接(axis不能为0),因为第二维度尺寸不同。
7. cv2.warpPerspective()
cv2.warpPespective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageA.shape[0])) # 获得根据单应性矩阵变化后的图像
# image表示输入图像,H表示单应性的矩阵,(imageA.shape[1] + imageB.shape[1], imageA.shape[0])表示矩阵变化后的维度
8. sift.detectAndComputer()
sift.detectAndComputer(gray, None) # 计算出图像的关键点和sift特征向量,gray表示输入的图片
9. np.reshape()
numpy.reshape(a, newshape, order='C')
# a 需要reshape的array,可以看成是对数组的扩展,但是不影响原始数组
# 关于newshape参数
np.reshape(m,n) # 返回一个m行n列的数组
np.reshape(-1) # 返回一个一维数组
np.reshape(-1,n) # 返回一个n列的数组,行数自动给定
np.reshape(k,n,m) # 创建一个三维 (k个n*m)的数组
np.reshape(p,k,n,m) # 四维 p个(k,n,m)# order: 可选为(C, F, A)
C: 按照行来填充
F: 按照列的顺序来填充
A: 按任意方向,默认,这里相当于行
arr=np.array([1,2,3,4,5,6,7,8,9,10,11,12])
m=arr.reshape(3,4)
print(m)>>
[[ 1 2 3 4][ 5 6 7 8][ 9 10 11 12]]m=arr.reshape(3,2,2)>>
[[[ 1 2][ 3 4]][[ 5 6][ 7 8]][[ 9 10][11 12]]]m=arr.reshape(2,3,1,2)>>
[[[[ 1 2]][[ 3 4]][[ 5 6]]][[[ 7 8]][[ 9 10]][[11 12]]]]
当newshape参数大于2个的时候,pylint就开始报参数过多的错 ?
官方文档
步骤:
- 读入图像,
- 用SIFT/SURF/FAST/ORB提取每张图的特征点 和 每个特征点对应的描述子
- 通过匹配特征点描述子,找到两张图中匹配的特征点对(这里可能存在错误匹配)
- 使用RANSAC算法剔除错误匹配
- 求解方程组,计算Homograph单应性变换矩阵
- 通过Homograph单应性变换矩阵对其中一张图片进行仿射变换
- 拼接图片
1.彩色图像的直方图均衡化
直方图均衡化
就是对图像进行非线性拉伸
,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。
中心思想:
原始图像的灰度直方图从比较集中的某个
灰度区间变成在全部灰度范围内
的均匀
分布
def equalize_histogram_color(img):img_yuv=cv2.cvtColor(img,cv2.COLOR_BGR2YUV)img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0])img = cv2.cvtColor(img_yuv,cv2.COLOR_YUV2BGR)return img
为什么要做直方图均衡化?
一副高质量的图像的像素值分布应该很广泛
,所以应该把它的直方图做一个横向拉伸,这就是直方图均衡化要做的事情。通常情况下这种操作会改善图像的对比度
。
2.特征点匹配和计算单应矩阵
def get_sift_homography(img1, img2):#特征提取# 初始化SIFTsift=cv2.xfeatures2d.SIFT_create() # 修改点 版本原因#提取关键点和描述子k1,d1=sift.detectAndCompute(img1,None) # k1存储提取的特征点,d1存储对应的描述子k2,d2=sift.detectAndCompute(img2,None)#图片匹配# 描述子计算:k-最邻近匹配bf=cv2.BFMatcher()matches=bf.knnMatch(d1,d2, k=2)# 获得理想匹配verify_ratio=0.8 # Source: stackoverflowverified_matches=[]for m1,m2 in matches:# 只加入理想匹配if m1.distance<0.8*m2.distance:verified_matches.append(m1)# 最少匹配数min_matches=8if len(verified_matches)>min_matches:# 存储匹配点img1_pts=[]img2_pts=[]# 把匹配点加进去for match in verified_matches:img1_pts.append(k1[match.queryIdx].pt)img2_pts.append(k2[match.trainIdx].pt)img1_pts=np.float32(img1_pts).reshape(-1,1,2)img2_pts=np.float32(img2_pts).reshape(-1,1,2)# 计算单应矩阵M,掩模 mark,使用了RANSAC算法剔初错误匹配M,mask=cv2.findHomography(img1_pts,img2_pts,cv2.RANSAC,5.0) return Melse: # 如果不够最小匹配数print('Error: Not enough matches')exit()
3.拼接图片
# 使用关键点来拼接图片
def get_stitched_image(img1,img2,M):# 获得输入图片的宽、高w1,h1=img1.shape[:2]w2,h2=img2.shape[:2]# 获得图像维度img1_dims=np.float32([[0,0],[0,w1],[h1,w1],[h1,0]]).reshape(-1,1,2)img2_dims_temp=np.float32([[0,0],[0,w2],[h2,w2],[h2,0]]).reshape(-1,1,2)# 获取第二幅图像的相对透视图img2_dims=cv2.perspectiveTransform(img2_dims_temp,M) # 执行矢量的透视矩阵变换# 得到结果图片的维度result_dims=np.concatenate((img1_dims,img2_dims),axis=0)# 拼接图像# 计算匹配点的维度[x_min,y_min]=np.int32(result_dims.min(axis=0).ravel()-0.5)[x_max,y_max]=np.int32(result_dims.max(axis=0).ravel()+0.5)# 仿射变换后创建输出数组transform_dist=[-x_min,-y_min]transform_array=np.array([[1, 0, transform_dist[0]], [0, 1, transform_dist[1]], [0,0,1]]) # 扭曲图像以用于拼接result_img=cv2.warpPerspective(img2,transform_array.dot(M), (x_max-x_min,y_max-y_min))result_img[transform_dist[1]:w1+transform_dist[1], transform_dist[0]:h1+transform_dist[0]]=img1# Return the resultreturn result_img
参考链接:Python+OpenCV实现图像的全景拼接
几个修改点
1. >83 print
后需要带括号输出 版本原因
2. >45 module ‘cv2’ has no attribute ‘SIFT’ 版本原因
3.4.2
版本中,openCV将SIFT等算法整合到xfeatures2d集合里面了
把sift=cv2.SIFT()
变成sift=cv2.xfeatures2d.SIFT_create()
3. >97 98 关于读入图像cv2.imread()
函数的使用
# 一直越界报错 (可能是我环境下的命令行参数没有配置好)
img1 = cv2.imread(sys.argv[1])
img2 = cv2.imread(sys.argv[2])
需要修改成路径形式
注意:
1.路径形式不支持 单右斜线
形式,可以支持 双右斜线、双左斜线、单左斜线形式、混合形式
#include<opencv2\opencv.hpp>
using namespace cv;
int main(int argc,char* argv[])
{Mat img;//-- 1 --双右斜线法//string imgpath = "C:\\Users\\bingbuyu\\Pictures\\photo\\miao1.jpg";//-- 2 --双左斜线法//string imgpath = "C://Users//bingbuyu//Pictures//photo//miao1.jpg";//-- 3 --单左斜线法//string imgpath = "C:/Users/bingbuyu/Pictures/photo/miao1.jpg";//-- 4 --以上三种混合法//string imgpath = "C:/Users//bingbuyu\\Pictures//photo//miao1.jpg";//-- 5 --相对路径法//string imgpath = "miao.jpg";//-- 6 --命令行参数法string imgpath = argv[1];img = imread(imgpath, 1);imshow("img", img);waitKey(0);return 0;
}
参考链接:使用imread()函数读取图片的六种正确姿势
2.命令行参数法
Python中 sys.argv[]的用法简明解释
4. >115 写入时,同样是由sys.argv[]
引起的越界错误,写入时需要带后缀名
写入
不能为imwrite()找到特定扩展名的writer,因为result_image_name
必须是.png
或.jpg
或.bmg
,改成带后缀的即可。
虽然能跑出来,但是有个报错没整明白 :是因为多于了2个newshape参数,变三维、四维数组的时候就会报这个,但还是可以用
方法调用的位置参数过多?reshape()
?
完整代码:
import sys
import cv2
import numpy as np
# Use the keypoints to stitch the images
def get_stitched_image(img1,img2,M):# Get width and height of input images w1,h1=img1.shape[:2]w2,h2=img2.shape[:2]# Get the canvas dimesionsimg1_dims=np.float32([[0,0],[0,w1],[h1,w1],[h1,0]]).reshape(-1,1,2)img2_dims_temp=np.float32([[0,0],[0,w2],[h2,w2],[h2,0]]).reshape(-1,1,2)# Get relative perspective of second imageimg2_dims=cv2.perspectiveTransform(img2_dims_temp,M)# Resulting dimensionsresult_dims=np.concatenate((img1_dims,img2_dims),axis=0)# Getting images together# Calculate dimensions of match points[x_min,y_min]=np.int32(result_dims.min(axis=0).ravel()-0.5)[x_max,y_max]=np.int32(result_dims.max(axis=0).ravel()+0.5)# Create output array after affine transformation transform_dist=[-x_min,-y_min]transform_array=np.array([[1, 0, transform_dist[0]], [0, 1, transform_dist[1]], [0,0,1]]) # Warp images to get the resulting imageresult_img=cv2.warpPerspective(img2,transform_array.dot(M), (x_max-x_min,y_max-y_min))result_img[transform_dist[1]:w1+transform_dist[1], transform_dist[0]:h1+transform_dist[0]]=img1# Return the resultreturn result_img# Find SIFT and return Homography Matrix
def get_sift_homography(img1, img2):# Initialize SIFT sift=cv2.xfeatures2d.SIFT_create() #修改点 版本原因# Extract keypoints and descriptorsk1,d1=sift.detectAndCompute(img1,None)k2,d2=sift.detectAndCompute(img2,None)# Bruteforce matcher on the descriptorsbf=cv2.BFMatcher()matches=bf.knnMatch(d1,d2, k=2)# Make sure that the matches are goodverify_ratio=0.8 # Source: stackoverflowverified_matches=[]for m1,m2 in matches:# Add to array only if it's a good matchif m1.distance<0.8*m2.distance:verified_matches.append(m1)# Mimnum number of matchesmin_matches=8if len(verified_matches)>min_matches:# Array to store matching pointsimg1_pts=[]img2_pts=[]# Add matching points to arrayfor match in verified_matches:img1_pts.append(k1[match.queryIdx].pt)img2_pts.append(k2[match.trainIdx].pt)img1_pts=np.float32(img1_pts).reshape(-1,1,2)img2_pts=np.float32(img2_pts).reshape(-1,1,2)# Compute homography matrixM,mask=cv2.findHomography(img1_pts,img2_pts,cv2.RANSAC,5.0)return Melse:print('Error: Not enough matches')exit()# Equalize Histogram of Color Images
def equalize_histogram_color(img):img_yuv=cv2.cvtColor(img,cv2.COLOR_BGR2YUV)img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0])img = cv2.cvtColor(img_yuv,cv2.COLOR_YUV2BGR)return img# Main function definition
def main():# Get input set of imagesimg1=cv2.imread("/Applications/code/test/01_suburbA.jpg") #修改点img2=cv2.imread("/Applications/code/test/01_suburbB.jpg")# Equalize histogramimg1=equalize_histogram_color(img1)img2=equalize_histogram_color(img2)# Show input imagesinput_images=np.hstack((img1,img2))cv2.imshow('Input Images',input_images)# Use SIFT to find keypoints and return homography matrixM=get_sift_homography(img1, img2)# Stitch the images together using homography matrixresult_image=get_stitched_image(img2,img1,M)# Write the result to the same directoryresult_image_name='result.jpg' #需要带后缀写入cv2.imwrite(result_image_name,result_image)# Show the resulting imagecv2.imshow('Result',result_image)cv2.waitKey()# Call main function
if __name__=='__main__':main()
GitHub
Image-Stitching
学习源码来自Github-pavanpn/Image-Stitching
主要函数:
1. cv2.cvtColor()
颜色空间转换函数
img_yuv=cv2.cvtColor(img,k) # img是需要转换对图片,k是转换成何种格式
# cv2.COLOR_BGR2RGB 将BGR格式转换成RGB格式
# cv2.COLOR_BGR2GRAY 将BGR格式转换成灰度图片
2. cv2.equalizeHist()
直方图均衡化函数
cv2.equalizeHist(img) # 将要均衡化的原图像[要求是灰度图像]作为参数传入,则返回值即为均衡化后的图像
3. bf=cv2.BFMatcher()、matches=bf.knnMatch()
K-最邻近匹配
# 暴力匹配BFMatcher,遍历描述符,确定描述符是否匹配,然后计算匹配距离并排序
# BFMatcher函数参数:
# normType:NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2。
# NORM_L1和NORM_L2是SIFT和SURF描述符的优先选择
# NORM_HAMMING和NORM_HAMMING2是用于ORB算法
bf = cv2.BFMatcher(normType=cv2.NORM_HAMMING, crossCheck=True)
matches = bf.knnMatch(d1, d2, k=1) #获得knn检测器,d1,d2为描述子
# knn匹配可以返回k个最佳的匹配项,bf返回所有的匹配项
4. cv2.findHomography()
单应矩阵发现函数
M,mask=cv2.findHomography(img1_pts,img2_pts,cv2.RANSAC,5.0)
# img1_pts 目标图像的特征点集合
# 第三个参数 配准方法的选择
# 第四个参数 每次抽取样本的个数,仅RANSAC和RHO有
5. cv2.perspectiveTransform()
透视变换函数
cv2.perspectiveTransform(src, m[, dst]) → dst
# src:输入的2通道或者3通道的图片
# m:变换矩阵
6. np.concatenate()
result_dims=np.concatenate((img1_dims,img2_dims),axis=0)
# 前两个参数为要拼接对数组
# axis参数为指定按照哪个维度进行拼接,axis=0则代表着按照第一维度进行拼接
上述两个数组不能按行拼接(axis不能为0),因为第二维度尺寸不同。
7. cv2.warpPerspective()
cv2.warpPespective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageA.shape[0])) # 获得根据单应性矩阵变化后的图像
# image表示输入图像,H表示单应性的矩阵,(imageA.shape[1] + imageB.shape[1], imageA.shape[0])表示矩阵变化后的维度
8. sift.detectAndComputer()
sift.detectAndComputer(gray, None) # 计算出图像的关键点和sift特征向量,gray表示输入的图片
9. np.reshape()
numpy.reshape(a, newshape, order='C')
# a 需要reshape的array,可以看成是对数组的扩展,但是不影响原始数组
# 关于newshape参数
np.reshape(m,n) # 返回一个m行n列的数组
np.reshape(-1) # 返回一个一维数组
np.reshape(-1,n) # 返回一个n列的数组,行数自动给定
np.reshape(k,n,m) # 创建一个三维 (k个n*m)的数组
np.reshape(p,k,n,m) # 四维 p个(k,n,m)# order: 可选为(C, F, A)
C: 按照行来填充
F: 按照列的顺序来填充
A: 按任意方向,默认,这里相当于行
arr=np.array([1,2,3,4,5,6,7,8,9,10,11,12])
m=arr.reshape(3,4)
print(m)>>
[[ 1 2 3 4][ 5 6 7 8][ 9 10 11 12]]m=arr.reshape(3,2,2)>>
[[[ 1 2][ 3 4]][[ 5 6][ 7 8]][[ 9 10][11 12]]]m=arr.reshape(2,3,1,2)>>
[[[[ 1 2]][[ 3 4]][[ 5 6]]][[[ 7 8]][[ 9 10]][[11 12]]]]
当newshape参数大于2个的时候,pylint就开始报参数过多的错 ?
官方文档
步骤:
- 读入图像,
- 用SIFT/SURF/FAST/ORB提取每张图的特征点 和 每个特征点对应的描述子
- 通过匹配特征点描述子,找到两张图中匹配的特征点对(这里可能存在错误匹配)
- 使用RANSAC算法剔除错误匹配
- 求解方程组,计算Homograph单应性变换矩阵
- 通过Homograph单应性变换矩阵对其中一张图片进行仿射变换
- 拼接图片
1.彩色图像的直方图均衡化
直方图均衡化
就是对图像进行非线性拉伸
,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。
中心思想:
原始图像的灰度直方图从比较集中的某个
灰度区间变成在全部灰度范围内
的均匀
分布
def equalize_histogram_color(img):img_yuv=cv2.cvtColor(img,cv2.COLOR_BGR2YUV)img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0])img = cv2.cvtColor(img_yuv,cv2.COLOR_YUV2BGR)return img
为什么要做直方图均衡化?
一副高质量的图像的像素值分布应该很广泛
,所以应该把它的直方图做一个横向拉伸,这就是直方图均衡化要做的事情。通常情况下这种操作会改善图像的对比度
。
2.特征点匹配和计算单应矩阵
def get_sift_homography(img1, img2):#特征提取# 初始化SIFTsift=cv2.xfeatures2d.SIFT_create() # 修改点 版本原因#提取关键点和描述子k1,d1=sift.detectAndCompute(img1,None) # k1存储提取的特征点,d1存储对应的描述子k2,d2=sift.detectAndCompute(img2,None)#图片匹配# 描述子计算:k-最邻近匹配bf=cv2.BFMatcher()matches=bf.knnMatch(d1,d2, k=2)# 获得理想匹配verify_ratio=0.8 # Source: stackoverflowverified_matches=[]for m1,m2 in matches:# 只加入理想匹配if m1.distance<0.8*m2.distance:verified_matches.append(m1)# 最少匹配数min_matches=8if len(verified_matches)>min_matches:# 存储匹配点img1_pts=[]img2_pts=[]# 把匹配点加进去for match in verified_matches:img1_pts.append(k1[match.queryIdx].pt)img2_pts.append(k2[match.trainIdx].pt)img1_pts=np.float32(img1_pts).reshape(-1,1,2)img2_pts=np.float32(img2_pts).reshape(-1,1,2)# 计算单应矩阵M,掩模 mark,使用了RANSAC算法剔初错误匹配M,mask=cv2.findHomography(img1_pts,img2_pts,cv2.RANSAC,5.0) return Melse: # 如果不够最小匹配数print('Error: Not enough matches')exit()
3.拼接图片
# 使用关键点来拼接图片
def get_stitched_image(img1,img2,M):# 获得输入图片的宽、高w1,h1=img1.shape[:2]w2,h2=img2.shape[:2]# 获得图像维度img1_dims=np.float32([[0,0],[0,w1],[h1,w1],[h1,0]]).reshape(-1,1,2)img2_dims_temp=np.float32([[0,0],[0,w2],[h2,w2],[h2,0]]).reshape(-1,1,2)# 获取第二幅图像的相对透视图img2_dims=cv2.perspectiveTransform(img2_dims_temp,M) # 执行矢量的透视矩阵变换# 得到结果图片的维度result_dims=np.concatenate((img1_dims,img2_dims),axis=0)# 拼接图像# 计算匹配点的维度[x_min,y_min]=np.int32(result_dims.min(axis=0).ravel()-0.5)[x_max,y_max]=np.int32(result_dims.max(axis=0).ravel()+0.5)# 仿射变换后创建输出数组transform_dist=[-x_min,-y_min]transform_array=np.array([[1, 0, transform_dist[0]], [0, 1, transform_dist[1]], [0,0,1]]) # 扭曲图像以用于拼接result_img=cv2.warpPerspective(img2,transform_array.dot(M), (x_max-x_min,y_max-y_min))result_img[transform_dist[1]:w1+transform_dist[1], transform_dist[0]:h1+transform_dist[0]]=img1# Return the resultreturn result_img
参考链接:Python+OpenCV实现图像的全景拼接
几个修改点
1. >83 print
后需要带括号输出 版本原因
2. >45 module ‘cv2’ has no attribute ‘SIFT’ 版本原因
3.4.2
版本中,openCV将SIFT等算法整合到xfeatures2d集合里面了
把sift=cv2.SIFT()
变成sift=cv2.xfeatures2d.SIFT_create()
3. >97 98 关于读入图像cv2.imread()
函数的使用
# 一直越界报错 (可能是我环境下的命令行参数没有配置好)
img1 = cv2.imread(sys.argv[1])
img2 = cv2.imread(sys.argv[2])
需要修改成路径形式
注意:
1.路径形式不支持 单右斜线
形式,可以支持 双右斜线、双左斜线、单左斜线形式、混合形式
#include<opencv2\opencv.hpp>
using namespace cv;
int main(int argc,char* argv[])
{Mat img;//-- 1 --双右斜线法//string imgpath = "C:\\Users\\bingbuyu\\Pictures\\photo\\miao1.jpg";//-- 2 --双左斜线法//string imgpath = "C://Users//bingbuyu//Pictures//photo//miao1.jpg";//-- 3 --单左斜线法//string imgpath = "C:/Users/bingbuyu/Pictures/photo/miao1.jpg";//-- 4 --以上三种混合法//string imgpath = "C:/Users//bingbuyu\\Pictures//photo//miao1.jpg";//-- 5 --相对路径法//string imgpath = "miao.jpg";//-- 6 --命令行参数法string imgpath = argv[1];img = imread(imgpath, 1);imshow("img", img);waitKey(0);return 0;
}
参考链接:使用imread()函数读取图片的六种正确姿势
2.命令行参数法
Python中 sys.argv[]的用法简明解释
4. >115 写入时,同样是由sys.argv[]
引起的越界错误,写入时需要带后缀名
写入
不能为imwrite()找到特定扩展名的writer,因为result_image_name
必须是.png
或.jpg
或.bmg
,改成带后缀的即可。
虽然能跑出来,但是有个报错没整明白 :是因为多于了2个newshape参数,变三维、四维数组的时候就会报这个,但还是可以用
方法调用的位置参数过多?reshape()
?
完整代码:
import sys
import cv2
import numpy as np
# Use the keypoints to stitch the images
def get_stitched_image(img1,img2,M):# Get width and height of input images w1,h1=img1.shape[:2]w2,h2=img2.shape[:2]# Get the canvas dimesionsimg1_dims=np.float32([[0,0],[0,w1],[h1,w1],[h1,0]]).reshape(-1,1,2)img2_dims_temp=np.float32([[0,0],[0,w2],[h2,w2],[h2,0]]).reshape(-1,1,2)# Get relative perspective of second imageimg2_dims=cv2.perspectiveTransform(img2_dims_temp,M)# Resulting dimensionsresult_dims=np.concatenate((img1_dims,img2_dims),axis=0)# Getting images together# Calculate dimensions of match points[x_min,y_min]=np.int32(result_dims.min(axis=0).ravel()-0.5)[x_max,y_max]=np.int32(result_dims.max(axis=0).ravel()+0.5)# Create output array after affine transformation transform_dist=[-x_min,-y_min]transform_array=np.array([[1, 0, transform_dist[0]], [0, 1, transform_dist[1]], [0,0,1]]) # Warp images to get the resulting imageresult_img=cv2.warpPerspective(img2,transform_array.dot(M), (x_max-x_min,y_max-y_min))result_img[transform_dist[1]:w1+transform_dist[1], transform_dist[0]:h1+transform_dist[0]]=img1# Return the resultreturn result_img# Find SIFT and return Homography Matrix
def get_sift_homography(img1, img2):# Initialize SIFT sift=cv2.xfeatures2d.SIFT_create() #修改点 版本原因# Extract keypoints and descriptorsk1,d1=sift.detectAndCompute(img1,None)k2,d2=sift.detectAndCompute(img2,None)# Bruteforce matcher on the descriptorsbf=cv2.BFMatcher()matches=bf.knnMatch(d1,d2, k=2)# Make sure that the matches are goodverify_ratio=0.8 # Source: stackoverflowverified_matches=[]for m1,m2 in matches:# Add to array only if it's a good matchif m1.distance<0.8*m2.distance:verified_matches.append(m1)# Mimnum number of matchesmin_matches=8if len(verified_matches)>min_matches:# Array to store matching pointsimg1_pts=[]img2_pts=[]# Add matching points to arrayfor match in verified_matches:img1_pts.append(k1[match.queryIdx].pt)img2_pts.append(k2[match.trainIdx].pt)img1_pts=np.float32(img1_pts).reshape(-1,1,2)img2_pts=np.float32(img2_pts).reshape(-1,1,2)# Compute homography matrixM,mask=cv2.findHomography(img1_pts,img2_pts,cv2.RANSAC,5.0)return Melse:print('Error: Not enough matches')exit()# Equalize Histogram of Color Images
def equalize_histogram_color(img):img_yuv=cv2.cvtColor(img,cv2.COLOR_BGR2YUV)img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0])img = cv2.cvtColor(img_yuv,cv2.COLOR_YUV2BGR)return img# Main function definition
def main():# Get input set of imagesimg1=cv2.imread("/Applications/code/test/01_suburbA.jpg") #修改点img2=cv2.imread("/Applications/code/test/01_suburbB.jpg")# Equalize histogramimg1=equalize_histogram_color(img1)img2=equalize_histogram_color(img2)# Show input imagesinput_images=np.hstack((img1,img2))cv2.imshow('Input Images',input_images)# Use SIFT to find keypoints and return homography matrixM=get_sift_homography(img1, img2)# Stitch the images together using homography matrixresult_image=get_stitched_image(img2,img1,M)# Write the result to the same directoryresult_image_name='result.jpg' #需要带后缀写入cv2.imwrite(result_image_name,result_image)# Show the resulting imagecv2.imshow('Result',result_image)cv2.waitKey()# Call main function
if __name__=='__main__':main()