OpenCV 4.2.0断言错误求助:calcOpticalFlowPyrLK调用失败
问题分析与解决
错误原因
你遇到的断言错误Assertion failed ((npoints = prevPtsMat.checkVector(2, CV_32F, true)) >= 0),本质是调用calcOpticalFlowPyrLK时,传入的prevPoints为空向量,或者向量内的点格式不符合要求。
常见触发场景:
- 首次调用
goodFeaturesToTrack时,没有从第一帧检测到任何特征点,导致prevPoints为空 - 后续循环中,光流追踪的所有点都失效(
status全为0),直接交换currPoints和prevPoints后,prevPoints变为空
修复后的代码
#include <opencv2/opencv.hpp> #include <vector> #include <algorithm> int main() { cv::VideoCapture cap("video.mp4"); if (!cap.isOpened()) { std::cerr << "无法打开视频文件或流。" << std::endl; return -1; } cv::Mat prevFrame, currFrame; cv::TermCriteria termcrit(cv::TermCriteria::COUNT | cv::TermCriteria::EPS, 20, 0.03); cv::Size winSize(31, 31); std::vector<cv::Point2f> prevPoints, currPoints; while (true) { cap >> currFrame; if (currFrame.empty()) { break; } cv::Mat currGray; cv::cvtColor(currFrame, currGray, cv::COLOR_BGR2GRAY); if (prevFrame.empty()) { currGray.copyTo(prevFrame); // 检测特征点,同时检查是否成功获取点 cv::goodFeaturesToTrack(prevFrame, prevPoints, 100, 0.01, 10); // 如果没检测到点,跳过当前循环,继续读下一帧 if (prevPoints.empty()) { continue; } } std::vector<uchar> status; std::vector<float> err; // 确保prevPoints非空才调用光流计算 if (!prevPoints.empty()) { cv::calcOpticalFlowPyrLK(prevFrame, currGray, prevPoints, currPoints, status, err, winSize, 3, termcrit, 0, 0.001); // 过滤无效点,只保留追踪成功的点 std::vector<cv::Point2f> validPrevPoints, validCurrPoints; for (size_t i = 0; i < status.size(); i++) { if (status[i]) { validPrevPoints.push_back(prevPoints[i]); validCurrPoints.push_back(currPoints[i]); // 在彩色帧上绘制(注意不要在灰度图上画彩色) cv::circle(currFrame, validCurrPoints.back(), 3, cv::Scalar(0, 0, 255), -1); cv::line(currFrame, validPrevPoints.back(), validCurrPoints.back(), cv::Scalar(0, 255, 0)); } } // 更新prevPoints为有效点集 prevPoints.swap(validPrevPoints); currPoints.swap(validCurrPoints); // 如果有效点过少,重新检测特征点 if (prevPoints.size() < 10) { cv::goodFeaturesToTrack(currGray, prevPoints, 100, 0.01, 10); } } else { // prevPoints为空时重新检测 cv::goodFeaturesToTrack(currGray, prevPoints, 100, 0.01, 10); } cv::imshow("Optical flow", currFrame); if (cv::waitKey(30) == 'q') { break; } currGray.copyTo(prevFrame); } cv::destroyAllWindows(); return 0; }
关键修复点
- 避免灰度图绘制彩色异常:原代码将
currFrame转为灰度后直接绘制,彩色会显示异常,改为保留原彩色帧用于绘制,单独用灰度帧计算光流 - 特征点有效性检查:每次调用
calcOpticalFlowPyrLK前确保prevPoints非空;追踪后过滤无效点,只保留status[i]为true的点 - 自动重新检测特征点:当有效追踪点数量过少时,重新调用
goodFeaturesToTrack获取新的特征点,避免prevPoints为空 - 首次检测失败处理:如果第一帧没检测到特征点,跳过当前循环,继续读取下一帧重试
内容的提问来源于stack exchange,提问作者feinhein
相关产品推荐
相关产品推荐

