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

OpenCV保存CV_16U灰度视频丢失右半部分问题求助

回答

核心问题分析

画面右半部分丢失的直接原因是16位单通道(CV_16U)图像的内存步长(step)与VideoWriter的读取逻辑不匹配。你直接用aImage.data()构造cv::Mat时,如果原数据的行字节数不是mWidth * 2(CV_16U每个像素占2字节),会导致Mat的内存布局错位,VideoWriter读取时会把后续行的错误数据填充到当前行,最终出现画面截断。

日志显示FFmpeg插件加载正常,排除后端初始化故障;画质差是MJPEG有损压缩的特性,属于次要问题。

解决方法

方法1:修复Mat的内存布局(保留16位信息)

构造Mat时明确指定行步长,或者通过clone()创建内存连续的Mat,确保每一行的字节数符合VideoWriter的预期:

// 方式1:明确指定行步长(假设原数据每行字节数为mWidth*2)
const cv::Mat imgDisplay16(mHeight, mWidth, CV_16U, aImage.data(), mWidth * 2);
// 方式2:克隆Mat以强制内存连续对齐
const cv::Mat imgDisplay16 = cv::Mat(mHeight, mWidth, CV_16U, aImage.data()).clone();

// 初始化VideoWriter后务必检查是否成功打开
mWriter = std::make_unique<cv::VideoWriter>(
    "file.avi", 
    cv::VideoWriter::fourcc('M','J','P','G'), 
    10, 
    imgDisplay16.size(), 
    false // 单通道必须设为false
);

if (mWriter->isOpened()) {
    mWriter->write(imgDisplay16);
    // 记得在完成写入后释放资源
    mWriter.reset();
}

方法2:转换为8位单通道写入(兼容多数编码,改善画质)

如果不需要保留16位的高动态范围,可以将图像归一化到8位后写入,同时MJPEG对8位图像的压缩效果更稳定,画质问题也会缓解:

cv::Mat img8U;
// 将16位图像归一化到0-255的8位范围
cv::normalize(imgDisplay16, img8U, 0, 255, cv::NORM_MINMAX, CV_8U);

mWriter = std::make_unique<cv::VideoWriter>(
    "file.avi", 
    cv::VideoWriter::fourcc('M','J','P','G'), 
    10, 
    img8U.size(), 
    false
);

if (mWriter->isOpened()) {
    mWriter->write(img8U);
    mWriter.reset();
}

额外建议

  • 若追求更好的画质,可尝试无损或低损编码,比如cv::VideoWriter::fourcc('F','L','V','1')或cv::VideoWriter::fourcc('A','V','C','1')(需FFmpeg支持);
  • 始终通过isOpened()验证VideoWriter的初始化状态,避免无效写入操作;
  • 若原数据的行步长确实不等于mWidth*2,必须在构造Mat时明确传入正确的步长参数,否则内存布局错误会持续存在。

内容的提问来源于stack exchange,提问作者David Levy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 09:02:08