使用C++将UYUV(YUV422交错、BT709)转为RGB遇问题求助
尝试用C将UYUV格式(YUV422 Interleaved、BT709)的YUV文件转换为RGB,编写的程序运行时抛出OpenCV异常,提示「输入图像通道数无效:'VScn::contains(scn)',其中'scn'为1」。将输入Mat的类型改为CV_8UC2后无报错,但转换结果异常;对应的Python代码可正常完成转换并得到正确结果,需解决C代码的问题。
错误信息
terminating with uncaught exception of type cv::Exception: OpenCV(4.5.5) /build/master_pack-android/opencv/modules/imgproc/src/color.simd_helpers.hpp:92: error: (-2:Unspecified error) in function 'cv::impl::(anonymous namespace)::CvtHelper<cv::impl::(anonymous namespace)::Set<2, -1, -1>, cv::impl::(anonymous namespace)::Set<3, 4, -1>, cv::impl::(anonymous namespace)::Set<0, -1, -1>, cv::impl::(anonymous namespace)::NONE>::CvtHelper(cv::InputArray, cv::OutputArray, int) [VScn = cv::impl::(anonymous namespace)::Set<2, -1, -1>, VDcn = cv::impl::(anonymous namespace)::Set<3, 4, -1>, VDepth = cv::impl::(anonymous namespace)::Set<0, -1, -1>, sizePolicy = cv::impl::(anonymous namespace)::NONE]'
Invalid number of channels in input image:
'VScn::contains(scn)'
where
'scn' is 1
异常转换结果

原C++代码
Size iSize(1920,1080); int iYUV_Size = iSize.width * (iSize.height + iSize.height / 2); Mat mSrc_YUV420(cv::Size(iSize.width, iSize.height + iSize.height / 2),CV_8UC1); ifstream FileIn; FileIn.open(filename, ios::binary | ios::in); if (FileIn.is_open()) { FileIn.read((char*)mSrc_YUV420.data, iYUV_Size); FileIn.close(); } else { printf("[Error] Unable to Read the Input File! \n"); } Mat mSrc_RGB(cv::Size(iSize.width, iSize.height), CV_8UC1); cv::cvtColor(mSrc_YUV420, mSrc_RGB, COLOR_YUV2RGB_UYVY); cv::imwrite(output_filename, mSrc_RGB);
可正常运行的Python代码
with open(input_name, "rb") as src_file: raw_data = np.fromfile(src_file, dtype=np.uint8, count=img_width*img_height*2) im = raw_data.reshape(img_height, img_width, 2) rgb = cv2.cvtColor(im, cv2.COLOR_YUV2RGB_UYVY)
正确转换结果

问题分析与修正代码
问题根源
- 文件大小计算错误:UYUV是YUV422 interleaved格式,每个像素对应2字节(U-Y-V-Y交替存储),总大小应为
width * height * 2,而非原代码中YUV420格式的width*(height + height/2)。 - 输入Mat类型与尺寸错误:UYUV是2通道交错格式,需创建与原始图像同尺寸的
CV_8UC2类型Mat,原代码错误创建了单通道、尺寸为YUV420的Mat。 - 输出Mat类型错误:RGB图像为3通道,需创建
CV_8UC3类型Mat,原代码错误使用了单通道CV_8UC1。
修正后的C++代码
#include <opencv2/opencv.hpp> #include <fstream> using namespace cv; using namespace std; int main(int argc, char** argv) { if (argc != 3) { printf("Usage: %s <input_uyuv_file> <output_rgb_file>\n", argv[0]); return -1; } const char* filename = argv[1]; const char* output_filename = argv[2]; Size iSize(1920, 1080); // UYUV为YUV422 interleaved,总大小=宽×高×2 int iYUV_Size = iSize.width * iSize.height * 2; // 创建2通道Mat,尺寸与原始图像一致 Mat mSrc_YUV(iSize, CV_8UC2); ifstream FileIn; FileIn.open(filename, ios::binary | ios::in); if (FileIn.is_open()) { FileIn.read((char*)mSrc_YUV.data, iYUV_Size); FileIn.close(); } else { printf("[Error] Unable to Read the Input File! \n"); return -1; } // 创建3通道RGB Mat Mat mSrc_RGB(iSize, CV_8UC3); // 执行UYVY转RGB转换 cv::cvtColor(mSrc_YUV, mSrc_RGB, COLOR_YUV2RGB_UYVY); cv::imwrite(output_filename, mSrc_RGB); printf("转换完成,结果已保存至%s\n", output_filename); return 0; }
内容的提问来源于stack exchange,提问作者Netanel Hadad

