综述
单个相机视频画面尺寸有限,在需要全景展示的场景下,就需要将多个相机视频进行拼接融合,得到一张全景图。本文基于opencv实现一个视频拼接的demo,熟悉视频拼接流程和opencv接口。
demo
直接上代码吧,注释还是比较清楚的:
import cv2
import numpy as np
#print(cv2.getBuildInformation())
# 加载两个视频
cap1 = cv2.VideoCapture('m1.MOV')
cap2 = cv2.VideoCapture('m2.MOV')
if(cap1.isOpened() == False | cap2.isOpened()==False):
print("Opening video stream fail.")
# 获取视频帧速率
fps = cap1.get(cv2.CAP_PROP_FPS)
# 初始化视频帧索引
frame_index = 0
while True:
# 读取视频帧
ret1, frame1 = cap1.read()
ret2, frame2 = cap2.read()
if not ret1 or not ret2:
break
# 确保两个视频帧的索引相等
if frame_index % fps == 0:
# 转换为灰度图像
gray1 = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
# 使用ORB算法检测关键点
orb = cv2.ORB_create()
keypoints1, descriptors1 = orb.detectAndCompute(gray1, None)
keypoints2, descriptors2 = orb.detectAndCompute(gray2, None)
# 使用BFMatcher进行匹配
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(descriptors1, descriptors2)
# 按照距离排序并保留最佳匹配点对
matches = sorted(matches, key=lambda x: x.distance)
if len(matches) > 10:
# 计算单应性矩阵并应用图像变换
src_pts = np.float32([keypoints1[m.queryIdx].pt for m in matches]).reshape(-1, 1, 2)
dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in matches]).reshape(-1, 1, 2)
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
matchesMask = mask.ravel().tolist()
# 使用单应性矩阵对第一帧进行变换
h, w = frame1.shape[:2]
frame1_transformed = cv2.warpPerspective(frame1, M, (w, h))
# 将变换后的帧与第二帧进行混合
result = cv2.addWeighted(frame1_transformed, 0.5, frame2, 0.5, 0.0)
cv2.imshow('Aligned Videos', result)
cv2.waitKey(1)
frame_index += 1
# 释放视频资源并关闭窗口
cap1.release()
cap2.release()
cv2.destroyAllWindows()
该demo使用ORB算法检测关键点,使用BFMatcher进行特征匹配,然后使用RANSAC算法估计单应性矩阵,最后使用透视变换将第二个视频帧与第一个视频帧对齐。你可以根据需要调整参数来优化算法的性能。
结论
本人实测,ORB算法实时性还是比较好的,但是拼接结果一言难尽,可能还需要根据使用场景深入优化。
注:
关于VideoCapture,这里我得多说道几句,因为它困扰了我一天时间!
问题:直接运行上述代码cap1 = cv2.VideoCapture('m1.MOV') 报错
OpenCV: Couldn't read video stream from file "m11.MOV"
第一步:当然说检查文件名+文件路径
文件名正确,文件路径和demo代码在同一目录
问题还在!
第二步:网上查吧
网上查了一堆答案,都是说要安装对应的解码器
好的,安装ffmpeg,打印opencv配置表,安装成功,仍然报上述错误!
第三步:没思路?那就变着花样在网上查吧
终于,还是在官方说明中找到了答案。官方还是牛B的!
官方说明原文:
Pitfall: If the video file you are reading is in the same folder as your code,
simply specify the correct file name.
Else, you would have to specify the complete path to the video file.
也就是说:如果代码和视频文件中同一目录,直接传文件名即可,如果不在同一目录,那就需要传完整路径。
嗯,知道问题在哪了吧,还是路径问题!
哎?好像不对啊,我就是同一目录,传的正确文件名啊!
好像也是哦,前面好像吹官方吹早了,嘿嘿。。。
不过不要紧,官方虽然没直接解决问题,但提供了灵感:完整路径!
是的,直接改成完整路径就好了!!!
总结:
好吧,我发誓,以后遇到这种问题,不管三七二十一,先填个十五再说!
哦,不对,是先改成完整路径再说!