如何用OpenCV将独立YUV420指针数据转BGR并保存为JPEG?
解决YUV420P转JPEG的OpenCV异常问题
你的问题核心是错误地将平面格式的YUV420数据当成了交织格式的YCrCb来处理,导致OpenCV无法正确解析颜色通道,最终输出异常图像。下面给你两种可行的解决方案:
方法一:分通道处理后合并转换
这种方法更直观,适合理解YUV通道的处理逻辑:
// 1. 分别创建Y、U、V单通道Mat cv::Mat y_mat(cv::Size(1920, 1080), CV_8UC1, Y); // Y指针对应1920x1080的单通道数据 cv::Mat u_mat(cv::Size(960, 540), CV_8UC1, U); // U指针对应960x540的单通道数据 cv::Mat v_mat(cv::Size(960, 540), CV_8UC1, V); // V指针对应960x540的单通道数据 // 2. 将U、V通道缩放至与Y通道相同尺寸(因为YUV转BGR需要三通道尺寸一致) cv::Mat u_resized, v_resized; cv::resize(u_mat, u_resized, y_mat.size(), 0, 0, cv::INTER_LINEAR); cv::resize(v_mat, v_resized, y_mat.size(), 0, 0, cv::INTER_LINEAR); // 3. 合并三通道为YUV444格式的Mat std::vector<cv::Mat> yuv_channels = {y_mat, u_resized, v_resized}; cv::Mat yuv_mat; cv::merge(yuv_channels, yuv_mat); // 4. 转换为BGR格式并保存 cv::Mat bgr_mat; cv::cvtColor(yuv_mat, bgr_mat, cv::COLOR_YUV2BGR); cv::imwrite("/data/data/org.myproject.debug/files/pic1.jpg", bgr_mat);
方法二:直接用OpenCV内置的YUV420P转换(更高效)
OpenCV原生支持YUV420P(即I420格式)的转换,不需要手动缩放通道,步骤更简洁:
// 1. 计算YUV420P的总数据大小 int y_size = 1920 * 1080; int uv_size = 960 * 540; int total_size = y_size + uv_size * 2; // 2. 创建连续缓冲区,将Y、U、V数据依次拷贝进去 std::vector<uchar> yuv_buffer(total_size); memcpy(yuv_buffer.data(), Y, y_size); memcpy(yuv_buffer.data() + y_size, U, uv_size); memcpy(yuv_buffer.data() + y_size + uv_size, V, uv_size); // 3. 构造I420格式的Mat并转换为BGR cv::Mat yuv_i420(cv::Size(1920, 1080), CV_8UC1, yuv_buffer.data()); cv::Mat bgr_mat; cv::cvtColor(yuv_i420, bgr_mat, cv::COLOR_YUV2BGR_I420); // 4. 保存JPEG(可选:添加质量参数) std::vector<int> jpeg_params = {cv::IMWRITE_JPEG_QUALITY, 90}; // 质量0-100,默认95 cv::imwrite("/data/data/org.myproject.debug/files/pic1.jpg", bgr_mat, jpeg_params);
注意事项
- 确保Y、U、V三个指针指向的内存是有效的,且数据没有被提前释放或损坏;
- 确认宽高参数完全匹配:Y是1920x1080,U/V是其一半的分辨率(960x540),这是YUV420采样的标准规格;
- 如果你的YUV格式是YUV420SP(比如NV12/NV21),需要替换对应的转换码(比如
COLOR_NV122BGR),但根据你描述的三个独立指针,应该是YUV420P格式。
内容的提问来源于stack exchange,提问作者kakumanu-sudhir




