OpenCV摄像头识别QR码播放视频时warpPerspective断言错误如何解决
问题解决指南
你遇到的 OpenCV(4.5.3) Error: Assertion failed (_src.total() > 0) in cv::warpPerspective 报错,本质是调用warpPerspective时传入的输入图像为空,没有有效像素。你的代码存在多处逻辑漏洞会触发该问题,修复方案如下:
存在的问题清单
- 缺少视频打开成功校验:如果QR码对应的视频文件不存在、路径错误,
video.open()调用失败后仍然继续执行后续逻辑,读取到的视频帧为空 - 缺少视频帧读取校验:视频播放到末尾后,
video >> videoFrame会读取失败得到空帧,直接传入warpPerspective就会触发断言 - 缺少单应性矩阵校验:
findHomography计算失败时会返回空Mat,传入warpPerspective也会触发报错 - 逻辑顺序错误:你在未对
warpedFrame、warpedMask执行透视变换之前,就先调用了copyTo方法,此时两个Mat都是空对象,也会触发空输入错误
修正后的完整代码
#include "opencv2/opencv.hpp" using namespace cv; using namespace std; int main() { Mat cameraFrame, videoFrame; vector<Point2f> bbox; double width, height; VideoCapture camera(0), video; QRCodeDetector qrDecoder; string data; // 校验摄像头是否正常打开 if (!camera.isOpened()) { cout << "摄像头打开失败" << endl; return -1; } while (camera.read(cameraFrame)) { data = qrDecoder.detectAndDecode(cameraFrame, bbox); if (data.length() > 0 && bbox.size() == 4) // 额外校验QR码返回的边界点数量是否正常 { if (!video.isOpened()) { string videoPath = "../data/" + data + ".mp4"; video.open(videoPath); // 校验视频是否打开成功 if (!video.isOpened()) { cout << "视频文件打开失败:" << videoPath << endl; data.clear(); // 清空data避免重复尝试打开失败的视频 continue; } width = video.get(CAP_PROP_FRAME_WIDTH); height = video.get(CAP_PROP_FRAME_HEIGHT); } // 读取视频帧并校验 if (!(video >> videoFrame)) { // 视频播放结束后释放资源,下次扫描到QR码重新播放 video.release(); data.clear(); continue; } vector<Point2f> v_bbox{ Point2f(0, 0), Point2f(width,0), Point2f(width,height), Point2f(0, height) }; Mat H = findHomography(v_bbox, bbox); // 校验单应性矩阵是否有效 if (H.empty()) { continue; } Mat warpedFrame, warpedMask; // 先做透视变换,再执行copyTo操作,修正顺序 warpPerspective(videoFrame, warpedFrame, H, cameraFrame.size()); Mat mask(videoFrame.size(), CV_8UC1, Scalar(255)); warpPerspective(mask, warpedMask, H, cameraFrame.size()); warpedFrame.copyTo(cameraFrame, warpedMask); imshow("warpedFrame", warpedFrame); imshow("WarpedMask", warpedMask); } imshow("cam", cameraFrame); // 按ESC键退出 if (waitKey(1) == 27) { break; } } // 释放资源 camera.release(); if (video.isOpened()) { video.release(); } destroyAllWindows(); return 0; }
额外注意事项
- 确认
../data/路径下存在和QR码内容同名的mp4文件,路径可以根据你的实际存放位置调整 - 如果需要重复播放视频,可以在视频读取到末尾后调用
video.set(CAP_PROP_POS_FRAMES, 0)重置到第一帧,不用释放资源
内容的提问来源于stack exchange,提问作者윤재준
相关产品推荐
相关产品推荐

