如何使用OpenCV将YV12图像转为BGRA?非连续三分量平面怎么处理
实现方案
当YV12的Y、U、V分量分别存储在三个独立非连续平面时,你可以选择以下两种方式调用cvtColor完成转换:
方案1:全版本兼容,仅需一次内存拷贝(推荐)
该方案兼容性最强,常规分辨率下内存拷贝开销可忽略,是生产环境常用选择:
// 提前定义你持有的独立平面参数: // uint8_t* y_ptr:Y分量起始指针 // int y_stride:Y分量每行实际占用字节数(步长) // uint8_t* v_ptr:V分量起始指针(YV12格式V分量顺序在U之前) // int v_stride:V分量每行步长 // uint8_t* u_ptr:U分量起始指针 // int u_stride:U分量每行步长 // int width:图像宽度,int height:图像高度,需为偶数 int uv_width = width / 2; int uv_height = height / 2; // 1. 申请连续的YV12格式缓冲区 cv::Mat yuv_continuous(height * 3 / 2, width, CV_8UC1); // 2. 逐行拷贝Y分量到连续缓冲区 for (int row = 0; row < height; row++) { memcpy(yuv_continuous.ptr<uint8_t>(row), y_ptr + row * y_stride, width); } // 3. 逐行拷贝V分量到连续缓冲区 uint8_t* v_dst = yuv_continuous.ptr<uint8_t>(height); for (int row = 0; row < uv_height; row++) { memcpy(v_dst + row * width, v_ptr + row * v_stride, uv_width); } // 4. 逐行拷贝U分量到连续缓冲区 uint8_t* u_dst = yuv_continuous.ptr<uint8_t>(height + uv_height); for (int row = 0; row < uv_height; row++) { memcpy(u_dst + row * width, u_ptr + row * u_stride, uv_width); } // 5. 调用原有转换逻辑即可 cv::Mat dst; // OpenCV 3.x及以下用CV_YUV2BGRA_YV12,4.x及以上用cv::COLOR_YUV2BGRA_YV12 cv::cvtColor(yuv_continuous, dst, CV_YUV2BGRA_YV12);
方案2:零拷贝方案(适合内存紧张的嵌入式场景)
该方案无需额外申请连续缓冲区,直接复用原有三个平面的内存,仅支持OpenCV 3.4及以上版本:
int uv_width = width / 2; int uv_height = height / 2; // 1. 直接构造三个分量的Mat,复用原有内存,非连续平面只需传入正确步长即可 cv::Mat y_mat(height, width, CV_8UC1, y_ptr, y_stride); cv::Mat v_mat(uv_height, uv_width, CV_8UC1, v_ptr, v_stride); cv::Mat u_mat(uv_height, uv_width, CV_8UC1, u_ptr, u_stride); // 2. 将U、V分量上采样到和Y分量相同分辨率 cv::Mat v_up, u_up; cv::resize(v_mat, v_up, cv::Size(width, height), 0, 0, cv::INTER_NEAREST); cv::resize(u_mat, u_up, cv::Size(width, height), 0, 0, cv::INTER_NEAREST); // 3. 按Y、V、U顺序合并为三通道YUV Mat std::vector<cv::Mat> yuv_channels = {y_mat, v_up, u_up}; cv::Mat yuv_mat; cv::merge(yuv_channels, yuv_mat); // 4. 转换为BGRA格式 cv::Mat dst; // OpenCV 3.x及以下用CV_YCrCb2BGRA,4.x及以上用cv::COLOR_YCrCb2BGRA cv::cvtColor(yuv_mat, dst, CV_YCrCb2BGRA);
注意:如果转换后图像颜色异常,首先检查U、V分量的顺序是否正确,YV12的V分量顺序在U之前,如果你的存储顺序是U在前V在后,需要将转换码替换为对应I420格式的常量。
内容的提问来源于stack exchange,提问作者SteveH
相关产品推荐
相关产品推荐

