OpenCV调用BFMatcher匹配摄像头视频时触发断言失败报错
问题描述
使用ORB特征匹配实现本地参考图像与摄像头实时采集画面的特征匹配时,运行代码抛出如下OpenCV断言错误:
matches = bf.match(des1, des2) cv2.error: OpenCV(4.6.0) D:\a\opencv-python\opencv-python\opencv\modules\core\src\batch_distance.cpp:275: error: (-215:Assertion failed) type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U) in function 'cv::batchDistance'
将输入源替换为本地存储的样例视频时,匹配功能可正常运行;摄像头硬件工作正常,直接通过OpenCV读取并显示摄像头采集画面无异常。
代码中cv2.VideoCapture传入cv2.CAP_DSHOW参数的原因是:不添加该参数时,OpenCV会抛出编解码器不支持的错误。
复现代码
import cv2 import numpy as np img = cv2.imread("ketchup.jpg",0) cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) orb = cv2.ORB_create() while(True): ret, frame = cap.read() frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) kp1, des1 = orb.detectAndCompute(img, None) kp2, des2 = orb.detectAndCompute(frame, None) bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck = True) matches = bf.match(des1, des2) matches = sorted(matches, key = lambda x:x.distance) res = cv2.drawMatches(img, kp1, frame, kp2, matches[:10], None, flags=2) cv2.imshow('frame', res) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()
运行环境
- Python版本:3.7.9
- 操作系统:Windows 7
- 摄像头型号:SCB-0355N
故障原因
报错触发的核心原因是描述子为空:orb.detectAndCompute()在输入图像纹理不足、特征点数量为0时,会返回None作为描述子结果。摄像头实时采集的帧可能出现过曝、过暗、无有效纹理(比如对准纯色墙面)的情况,此时des2为None,直接传入bf.match()就会触发类型、维度校验失败的断言错误。
本地样例视频的帧普遍有足够纹理,极少出现描述子为空的情况,因此可以正常运行。
修复方法
在执行特征匹配前,增加两个描述子的非空校验,当任意一个描述子为空时跳过当前帧的匹配逻辑即可。同时补充摄像头读帧失败的判断,避免空帧传入后续逻辑。修复后的核心循环代码如下:
# 参考图特征可移到循环外只计算一次,减少冗余计算 kp1, des1 = orb.detectAndCompute(img, None) while(True): ret, frame = cap.read() if not ret: break frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) kp2, des2 = orb.detectAndCompute(frame, None) # 描述子非空校验 if des1 is None or des2 is None: # 无有效特征点时直接显示原始灰度帧 cv2.imshow('frame', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break continue bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck = True) matches = bf.match(des1, des2) matches = sorted(matches, key = lambda x:x.distance) res = cv2.drawMatches(img, kp1, frame, kp2, matches[:10], None, flags=2) cv2.imshow('frame', res) if cv2.waitKey(1) & 0xFF == ord('q'): break
额外优化提示:参考图是固定输入,其特征点和描述子不需要在循环内重复计算,移到循环外仅初始化一次即可,可明显降低运行时CPU占用。
内容的提问来源于stack exchange,提问作者Oleg Riabov
相关产品推荐
相关产品推荐

