YUV2 数据的 Channel 和 Bit 值

Posted

技术标签:

【中文标题】YUV2 数据的 Channel 和 Bit 值【英文标题】:Channel and Bit values of a YUV2 data 【发布时间】:2012-07-18 12:49:57 【问题描述】:

我有一个来自相机(PAL)的数据流 我从回调函数中得到的数据类型是 U0-Y0-V0-Y1 U2-Y2-V2-Y3 U4-Y4-V4-Y5 ......

我需要使用 OpenCV 的 cvCvtColor() 函数将颜色格式更改为 RGB(或 BGR)。该函数的用法是 cvCvtColor(YCrCb, dst, CV_YCrCb2BGR); 现在这里(实际上是之前)出现了问题,dst 是一个 3 通道 8U 图像,没关系,但是如何将来自回调函数的数据直接存储在 IplImage 中?如果我可以正确存储它,我可以使用 cvCvtColor() 来转换图像。任何功能,任何其他库? 如果我在每一帧中使用 RGBYUV 数学转换,这会导致 70%++ 的 CPU 使用率,所以我不想使用它们,我正在寻找更简单的 CPU 方法。

【问题讨论】:

【参考方案1】:

如果您的输入格式是 YUY2,那么它实际上是 Y-U-Y-V,我下面的示例假设了这一点。但是,如果您的格式确实是 U-Y-V-Y,只需更改我示例中的顺序或颜色空间(请参阅下面的注释)。

您可以通过 2 通道 Mat 数组将此 YUY2/YUYV422 数据呈现给 OpenCV。

有两种方法可以填充 Mat img:通过复制和通过引用。根据您的应用程序,您可以选择其中任何一个。

两者都假设您在 char 数组 image_yuv 中有 yuv 数据。

1a。通过引用原始数据(没有 mem alloc;快速):

Mat img(height, width, CV_8UC2, img_yuv);

1b。通过将数据复制到 Mat 中:

Mat img(height, width, CV_8UC2);
uchar *pix = img.ptr<uchar>(r); // first byte of the row in image
for (int r = 0, b=0; r < height; r++) 
    for (int c = 0; c < width; c+=4) 
        *pix++ = image_yuv[b++]; // y
        *pix++ = image_yuv[b++]; // u
        *pix++ = image_yuv[b++]; // y
        *pix++ = image_yuv[b++]; // v
    

现在您已经在 Mat img 中拥有了数据,您可以使用 cvtColor 将其转换为其他颜色空间:

2a。更改为 BGR:

cvtColor(img, img_p, COLOR_YUV2BGR_YUY2);
imshow("window", img_p);

2b。改为灰度:

cvtColor(img, img_p, COLOR_YUV2GRAY_YUY2);
imshow("window", img_p);

注意:如果您的格式是 U-Y-V-Y,请更改复制顺序或更改颜色空间(COLOR_YUV2BGR_UYVY 或 COLOR_YUV2GRAY_UYVY)。请参阅 OpenCV 源代码中的 imgproc.hpp。

【讨论】:

为什么使用 CV_8UC2? YUV2 (YUYV422) 是 OpenCV 中的双平面格式。首先是 Y 平面,其次是 U & V 交错平面。我的代码将 OP 的传入数据从U0-Y0-V0-Y1 U2-Y2-V2-Y3 ... 格式解包并打包为两计划 YUV2 OpenCV 格式,因此使用了CV_8UC2【参考方案2】:

我会像这样为帧缓冲区制作一个 Iplimage 标头:

    IplImage* header = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 3);
    headercopy->widthStep = width*3;//I hope this will right for you... :)
    headercopy->imageData = (char*) bufferstart;

您现在可以将 Iplimage 标头用作普通的 Iplimage 希望就是这样。 对于转换,您可能需要分配一个新的 IplImage 对象!

【讨论】:

您的解决方案适用于 RGB 图像,如果 bufferLength 为 40(在 YUY2 中),则表示 RGB 的长度为 60 字节。但是您的代码通过假设 YUY2 的长度为 60 字节,直接将 YUY2 数据分配给 RGB 图像。因为 widthStep = widthStep*3 不适用于 YUY2。我可以通过一些计算找到widthStep,但是通道长度(3)将是另一个问题。我读过一些说法,例如 OpenCV 不直接支持 YUY 格式。需要自己进行转换:/ hmm 抱歉,现在我了解您的问题了...我认为 opencv 不会为您的数据流提供任何标准解决方案。如果我没看错,传感器输出 50% Y、25% U 和 25% V(看起来像 yuv 4:2:2 色度子采样)。这意味着您还必须对数据进行一些信号去马赛克处理。那种东西在opencv中没有实现(我不知道这些功能)。该信号仅知道每个像素的 Y(50%) 或 U(25%) 或 V(25%),因此您必须从邻居中重新插入另一个。你将不得不在这里做一些工程工作;)。【参考方案3】:

IIRC openCV 不支持交错 YUV,它只支持平面 YUV420/YUV422,其中整个图像的 Y 数据首先是降低分辨率的 U 和 V(JPEG 使用)

您可以将数据重新排序到平面中,也可以使用formulae here 或此答案Converting YUV->RGB(Image processing)->YUV during onPreviewFrame in android? 中更快的整数版本自己生成 RGB 数据

【讨论】:

【参考方案4】:

我还发现这段代码只是将 YUV 4:2:2 转换为 rgb 也许这可能有用.... convert YUV422 to RGB24(不是这个不是) 但也许我发现的这个其他网站可能更有用。他没有给出将图像转换为 opencv 标准 RGB24 的任何代码,因此您必须了解 c 代码并将其调整为 opencv 标准: http://wss.co.uk/pinknoise/yuv2rgb/

不知怎的,我找不到任何好的解决方案....

【讨论】:

以上是关于YUV2 数据的 Channel 和 Bit 值的主要内容,如果未能解决你的问题,请参考以下文章

go语言管道(channel)

go语言管道(channel)

netty4在channel.writeAndFlush为啥还阻塞延迟

yuv2mp4

[Go] 通过 17 个简短代码片段,切底弄懂 channel 基础

图像RGB2YUV与YUV2RGB格式互转介绍