如何使用Python+OpenCV检测视频中指定电锯并绘制外接矩形框
问题分析
- 仅使用了第一张参考图像的特征,其余3张参考图像未参与匹配,有效特征量不足,误匹配概率高
- 匹配对筛选逻辑过于简单,直接取前10个匹配结果,未过滤误匹配点,大量错误匹配点直接导致框选位置漂移
- 直接对匹配点取最大最小坐标画框,未考虑目标在视频中存在的旋转、缩放、视角变化,框选范围完全不符合实际目标位置
优化方案
- 4张参考图像全部参与特征匹配,每帧选择匹配有效点数量最多的参考图像结果计算目标位置
- 先用KNN匹配加距离阈值筛选粗筛匹配对,再通过RANSAC算法计算单应性矩阵,进一步过滤误匹配点
- 基于单应性矩阵将参考图像的四个角点透视变换到当前帧,再根据变换后的点计算外接矩形,适配目标的旋转、缩放、视角变化
修正后代码
import numpy as np import cv2 import matplotlib.pyplot as plt # 如不需要show_img函数可删除 def show_img(img, bw=False): fig = plt.figure(figsize=(13,13)) ax = fig.gca() ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.imshow(img, cmap='Greys_r' if bw else None) plt.show() # 读取所有参考图并预处理 ref_imgs = [] ref_grays = [] ref_kps = [] ref_des = [] ref_paths = ["saw1.jpg", "saw2.jpg", "saw3.jpg", "saw4.jpg"] for path in ref_paths: img = cv2.imread(path) ref_imgs.append(img) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ref_grays.append(gray) # 初始化ORB orb = cv2.ORB_create(nfeatures=2000) for gray in ref_grays: kp, des = orb.detectAndCompute(gray, None) ref_kps.append(kp) ref_des.append(des) # 初始化匹配器 matcher = cv2.BFMatcher(cv2.NORM_HAMMING) cap = cv2.VideoCapture('sawmovie.mp4') while cap.isOpened(): ret, frame = cap.read() if not ret: break frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) frame_kp, frame_des = orb.detectAndCompute(frame_gray, None) best_h = None max_good = 0 # 遍历所有参考图找匹配效果最好的 for i in range(4): if ref_des[i] is None or frame_des is None: continue # KNN匹配 matches = matcher.knnMatch(ref_des[i], frame_des, k=2) # 距离阈值筛选 good = [] for m, n in matches: if m.distance < 0.75 * n.distance: good.append(m) # 有效匹配点数量足够才计算单应性 if len(good) > 10 and len(good) > max_good: max_good = len(good) src_pts = np.float32([ref_kps[i][m.queryIdx].pt for m in good]).reshape(-1,1,2) dst_pts = np.float32([frame_kp[m.trainIdx].pt for m in good]).reshape(-1,1,2) # RANSAC过滤误匹配 H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) if H is not None: best_h = H best_ref_idx = i # 找到有效单应性矩阵则画框 if best_h is not None: h, w = ref_grays[best_ref_idx].shape # 参考图四个角点 ref_corners = np.float32([[0,0], [0,h-1], [w-1,h-1], [w-1,0]]).reshape(-1,1,2) # 变换到当前帧 frame_corners = cv2.perspectiveTransform(ref_corners, best_h) # 计算外接矩形 x,y,w,h = cv2.boundingRect(frame_corners) # 画框 cv2.rectangle(frame, (x,y), (x+w, y+h), (255,0,0), 2) cv2.imshow('Frame', frame) if cv2.waitKey(25) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()
运行说明
- 请将代码中参考图路径、视频路径替换为本地实际路径
- 可根据实际匹配效果调整ORB的
nfeatures参数、KNN匹配的距离阈值、RANSAC的重投影误差阈值参数 - 如果目标在视频中运动速度较快,可降低
waitKey的等待时长提升帧率
内容的提问来源于stack exchange,提问作者LordKroak
相关产品推荐
相关产品推荐

