You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCV VideoCapture读取图像序列后,复制帧显示异常如何解决?

问题分析:OpenCV手动复制图像帧到新Mat时显示异常

我尝试使用OpenCV的VideoCapture类从指定文件夹中顺序读取图像,图像读取功能正常,可正确查看读取图像(imgSrc)的视频流。但当我通过嵌套for循环将每一帧复制到新的Mat对象(imgDst)时,新图像与原图像不符,显示出现异常。请问我在操作中存在哪些错误导致了该问题?

原始代码

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void help(char** argv) {
 cout << "\nThis program gets you started reading a sequence of images using cv::VideoCapture.\n"
 << "Image sequences are a common way to distribute video data sets for computer vision.\n"
 << "Usage: " << argv[0] << " <path to the first image in the sequence>\n"
 << "example: " << argv[0] << " right%%02d.jpg\n"
 << "q,Q,esc -- quit\n"
 << "\tThis is a starter sample, to get you up and going in a copy paste fashion\n"
 << endl;
}
int main(int argc, char** argv) {
 if(argc != 2) {
 help(argv);
 return 1;
 }
 string arg = argv[1];
 VideoCapture sequence(arg);
 if (!sequence.isOpened()) {
 cerr << "Failed to open Image Sequence!\n" << endl;
 return 1;
 }
 Mat imgSrc; // source image
 for(;;) {
 sequence >> imgSrc;
 if(imgSrc.empty()) {
 cout << "End of Sequence" << endl;
 break;
 }
 Mat imgDst = cv::Mat::zeros(cv::Size(imgSrc.size().width,imgSrc.size().height),CV_16U);
 // Copying the elements of imgSrc to imgDst
 uint16_t* imgSrcPtr;
 uint16_t* imgDstPtr;
 for(int i = 0; i < imgSrc.rows; i++) {
 imgDstPtr = imgDst.ptr<uint16_t>(i);
 imgSrcPtr = imgSrc.ptr<uint16_t>(i);
 for(int j= 0; j < imgSrc.cols; j++)
 imgDstPtr[j] = imgSrcPtr[j];
 }
 namedWindow("Source image ",WINDOW_AUTOSIZE );
 namedWindow("Destination image ",WINDOW_AUTOSIZE );
 imshow("Destination image ", imgDst);
 waitKey(0;
 return 0;
 }
}

核心错误分析

1. 图像数据类型不匹配(最关键原因)

从VideoCapture读取的图像imgSrc默认是8位无符号整数类型(CV_8U),但你创建的imgDst是16位无符号整数类型(CV_16U)。

你用uint16_t*指针去访问imgSrc的内存,会导致严重的内存读取错误:

  • CV_8U每个像素占1字节,而uint16_t是2字节,所以imgSrcPtr[j]会一次性读取imgSrc中两个相邻的像素字节,将其拼接成一个16位值,完全扭曲了原始图像数据。
  • 这种类型不匹配会直接导致imgDst的像素值和原图像毫无关联,显示自然异常。

2. 程序提前终止,无法处理多帧

你的waitKey(0)和return 0写在了帧处理的循环内部:

  • waitKey(0)会阻塞程序直到你按下任意键,但紧接着的return 0会直接结束整个程序,导致你只能看到第一帧的错误结果,根本不会处理后续图像序列。
  • 另外waitKey(0)后面还少了一个闭合括号,属于语法错误,编译时应该会报错。

3. 不必要的重复窗口创建

你在每一次帧循环里都调用namedWindow创建窗口,虽然OpenCV会自动处理重复创建的情况,但这是冗余操作,应该把窗口创建放在循环之前,只执行一次。

4. 手动指针复制的风险

手动操作指针进行像素复制容易出错,比如类型不匹配、内存越界等,OpenCV本身提供了更安全高效的复制方法,没必要手动写嵌套循环。


修正后的代码示例

下面是修复所有问题后的代码:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;

void help(char** argv) {
 cout << "\nThis program gets you started reading a sequence of images using cv::VideoCapture.\n"
 << "Image sequences are a common way to distribute video data sets for computer vision.\n"
 << "Usage: " << argv[0] << " <path to the first image in the sequence>\n"
 << "example: " << argv[0] << " right%%02d.jpg\n"
 << "q,Q,esc -- quit\n"
 << "\tThis is a starter sample, to get you up and going in a copy paste fashion\n"
 << endl;
}

int main(int argc, char** argv) {
 if(argc != 2) {
 help(argv);
 return 1;
 }
 
 string arg = argv[1];
 VideoCapture sequence(arg);
 if (!sequence.isOpened()) {
 cerr << "Failed to open Image Sequence!\n" << endl;
 return 1;
 }

 // 提前创建窗口,只执行一次
 namedWindow("Source image ", WINDOW_AUTOSIZE);
 namedWindow("Destination image ", WINDOW_AUTOSIZE);

 Mat imgSrc; // source image
 for(;;) {
 sequence >> imgSrc;
 if(imgSrc.empty()) {
 cout << "End of Sequence" << endl;
 break;
 }

 // 方案1:创建和源图像同类型的目标图像,直接复制
 Mat imgDst;
 imgSrc.copyTo(imgDst); // 使用OpenCV内置的复制函数,安全高效

 // 如果你确实需要将图像转换为CV_16U类型,可以用下面的方案:
 // Mat imgDst;
 // imgSrc.convertTo(imgDst, CV_16U); // 将8位图像转换为16位,自动缩放像素值(0-255 -> 0-65535)

 // 显示图像
 imshow("Source image ", imgSrc);
 imshow("Destination image ", imgDst);

 // 等待30ms,按q/esc退出
 char key = waitKey(30);
 if(key == 'q' || key == 'Q' || key == 27) {
 break;
 }
 }

 return 0;
}

关键修复点说明

  • 匹配数据类型:要么让imgDst和imgSrc类型一致(用copyTo),要么显式转换类型(用convertTo),避免指针类型不匹配的问题。
  • 调整程序流程:把waitKey放在循环内,设置合适的等待时间(比如30ms),并添加退出逻辑;将return 0移到循环结束后。
  • 移除冗余操作:窗口创建移到循环外,只执行一次。
  • 使用OpenCV内置函数:copyTo和convertTo比手动指针操作更安全、高效,还能避免很多低级错误。

内容的提问来源于stack exchange,提问作者Taki Eddine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:42:55