Python + OpenCV 实现多路监控视频畸变矫正、手动/自动拼接融合与输出(港口/安防实战)

📅 2026/7/8 13:45:57
Python + OpenCV 实现多路监控视频畸变矫正、手动/自动拼接融合与输出(港口/安防实战)
Python OpenCV 实现多路监控视频畸变矫正、手动/自动拼接融合与输出港口/安防实战适用场景固定摄像头监控港口、园区、道路多路 RTSP 视频拼接成全景画面含畸变处理与后裁剪。一、整体流程多路 RTSP / 本地视频 ↓ ① 读取帧 ↓ ② 相机畸变矫正Undistortion广角/鱼眼需做 ↓ ③ 图像配准手动标注 Homography 或 自动 ORB/SIFT ↓ ④ 透视变换warpPerspective ↓ ⑤ 重叠区融合加权 / Multi-band Blending ↓ ⑥ 有效区域裁剪去除黑边多边形 ↓ ⑦ 编码输出 MP4 / 推流二、相机畸变标定仅需一次用棋盘格9×6拍摄 20~30 张不同角度import cv2 import numpy as np objp np.zeros((6 * 9, 3), np.float32) objp[:, :2] np.mgrid[0:9, 0:6].T.reshape(-1, 2) objpoints, imgpoints [], [] gray_shape None for fname in [calib1.jpg, calib2.jpg, ...]: img cv2.imread(fname) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray_shape gray.shape ret, corners cv2.findChessboardCorners(gray, (9, 6), None) if ret: objpoints.append(objp) imgpoints.append(corners) ret, mtx, dist, rvecs, tvecs cv2.calibrateCamera( objpoints, imgpoints, gray_shape[::-1], None, None ) np.savez(camera_params.npz, mtxmtx, distdist) print(✅ 相机参数已保存)去畸变函数def undistort(frame, params_pathcamera_params.npz): p np.load(params_path) return cv2.undistort(frame, p[mtx], p[dist])三、自动拼接相邻监控画面import cv2 img1 cv2.imread(cam_left.jpg) img2 cv2.imread(cam_right.jpg) stitcher cv2.Stitcher_create(cv2.Stitcher_PANORAMA) status, pano stitcher.stitch([img1, img2]) if status cv2.Stitcher_OK: cv2.imwrite(auto_stitch.jpg, pano)⚠️ 对斜拍角度大或低纹理场景可能失败此时用手动标定。四、手动标注 Homography固定监控推荐启动手动标定工具python manual_calib.py标定界面操作命令常用快捷键按键功能鼠标左键​在左图点一下 → 在右图对应位置点一下 添加一对对应点u​撤销最后一个点可连按按标注顺序倒着删r​清空当前这一对画面的全部点重新标n​当前对标定完成进入下一对画面s​跳过当前这对不标定p​预览当前拼接效果b​返回上一对q​保存当前所有标定点并退出​Esc​强制退出不保存标定流程示例1. 左图点击起重机吊臂顶端 → 右图点击同一位置 2. 左图点击集装箱左下角 → 右图点击同一位置 3. 重复直到点数 ≥ 4建议 6~8 对 4. 按 u 可撤销最后一个点如果点错了 5. 按 r 可清空所有点重新标 6. 按 n 进入下一对 7. 全部标完后按 q 保存退出手动标定核心代码import cv2 import numpy as np def manual_homography(img1, img2): pts1, pts2 [], [] def click1(e, x, y, flags, param): if e cv2.EVENT_LBUTTONDOWN: pts1.append([x, y]) cv2.circle(img1, (x, y), 4, (0,0,255), -1) cv2.imshow(Left, img1) def click2(e, x, y, flags, param): if e cv2.EVENT_LBUTTONDOWN: pts2.append([x, y]) cv2.circle(img2, (x, y), 4, (0,255,0), -1) cv2.imshow(Right, img2) cv2.imshow(Left, img1) cv2.imshow(Right, img2) cv2.setMouseCallback(Left, click1) cv2.setMouseCallback(Right, click2) print(点 ≥4 对后按 q 保存) while True: key cv2.waitKey(1) 0xFF if key ord(u) and pts1 and pts2: pts1.pop() pts2.pop() print(f撤销一个点剩余 {len(pts1)} 对) # 刷新显示 img1_copy img1.copy() img2_copy img2.copy() for p in pts1: cv2.circle(img1_copy, tuple(p), 4, (0,0,255), -1) for p in pts2: cv2.circle(img2_copy, tuple(p), 4, (0,255,0), -1) cv2.imshow(Left, img1_copy) cv2.imshow(Right, img2_copy) elif key ord(r): pts1.clear() pts2.clear() print(已清空所有点重新标) cv2.imshow(Left, img1.copy()) cv2.imshow(Right, img2.copy()) elif key ord(q): break cv2.destroyAllWindows() assert len(pts1) 4, f至少需要 4 对点当前只有 {len(pts1)} 对 H, _ cv2.findHomography( np.float32(pts1).reshape(-1,1,2), np.float32(pts2).reshape(-1,1,2), cv2.RANSAC, 5.0 ) return H H manual_homography(img1.copy(), img2.copy()) np.save(H_cam1_to_cam2.npy, H) print(✅ Homography 已保存)标注时显示的是红色 / 绿色实心小圆点●不是空心圈。五、融合 自动裁剪黑边def stitch_crop(img1, img2, H): h, w img1.shape[:2] pano cv2.warpPerspective(img1, H, (w*2, h)) # 简单加权融合重叠区 pano[:, :w] cv2.addWeighted(pano[:, :w], 0.5, img2, 0.5, 0) # 去黑边 gray cv2.cvtColor(pano, cv2.COLOR_BGR2GRAY) _, mask cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY) cnts, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) x, y, ww, hh cv2.boundingRect(max(cnts, keycv2.contourArea)) return pano[y:yhh, x:xww] result stitch_crop(img1, img2, np.load(H_cam1_to_cam2.npy)) cv2.imwrite(final_panorama.jpg, result)六、输出拼接视频MP4out cv2.VideoWriter( panorama.mp4, cv2.VideoWriter_fourcc(*mp4v), 25, (result.shape[1], result.shape[0]) ) while True: # 读取每帧 → undistort → warp → blend → crop out.write(stitched_frame) out.release()七、常用 OpenCV 拼接相关命令速查启动与基本操作命令说明python manual_calib.py启动手动标定工具鼠标左键​在左图/右图点击添加对应点u​撤销最后一个点可连按r​清空当前这对全部点重新标n​进入下一对画面s​跳过当前这对p​预览拼接效果b​返回上一对q​保存并退出Esc​强制退出不保存OpenCV API 速查功能API读取图片cv2.imread()显示窗口cv2.imshow()/cv2.waitKey()鼠标回调cv2.setMouseCallback()画圆点cv2.circle(img, (x,y), 4, color, -1)去畸变cv2.undistort()ORB 特征cv2.ORB_create()BFMatchercv2.BFMatcher()计算 H 矩阵cv2.findHomography(pts1, pts2, cv2.RANSAC)透视变换cv2.warpPerspective()全景拼接cv2.Stitcher_create().stitch()找轮廓cv2.findContours()最小外接矩形cv2.boundingRect()写视频cv2.VideoWriter()八、注意事项✅ 固定摄像头 →首帧标定一次后续复用 H 矩阵✅ 拼接后务必做mask 裁剪去黑边⚠️cv2.Stitcher对低纹理 / 大斜角敏感失败改用手动 Homography⚠️ 鱼眼需先用cv2.fisheye模块矫正不能直接undistort✅ 手动标定时按u可逐个撤销点按r可一键清空重标✅ 建议每对标6~8 个点均匀分布在重叠区域九、结语本文总结了 Python OpenCV 在安防监控场景下实现畸变矫正 → 手动/自动拼接 → 融合 → 裁剪输出的完整流程适用于港口、园区等多路固定监控的全景拼接需求。