在 OpenCV 中将 YUV 转换为 BGR 或 RGB

Posted

技术标签:

【中文标题】在 OpenCV 中将 YUV 转换为 BGR 或 RGB【英文标题】:Converting YUV into BGR or RGB in OpenCV 【发布时间】:2011-10-31 13:30:30 【问题描述】:

我有一个电视采集卡,它有一个 YUV 格式的提要。我在这里看到了与此问题类似的其他帖子,并尝试尝试说明的所有可能方法,但它们都没有提供清晰的图像。目前最好的结果是使用 OpenCV cvCvtColor(scr, dst, CV_YUV2BGR) 函数调用。

我目前不知道 YUV 格式,老实说让我有点困惑,因为它看起来像存储 4 个通道,但只有 3 个?我已经包含了捕获卡中的图像,希望有人能理解我可以用来填补空白的可能发生的事情。

提要通过 DeckLink Intensity Pro 卡进入,并在 Windows 7 环境中使用 OpenCV 的 C++ 应用程序中访问。

更新

我查看了有关此信息的***文章,并尝试在我的应用程序中使用该公式。下面是从它接收到输出的代码块。非常感谢任何建议。

BYTE* pData;

    videoFrame->GetBytes((void**)&pData);

    m_nFrames++;

    printf("Num Frames executed: %d\n", m_nFrames);

    for(int i = 0; i < 1280 * 720 * 3; i=i+3)
    
        m_RGB->imageData[i] = pData[i] + pData[i+2]*((1 - 0.299)/0.615);
        m_RGB->imageData[i+1] = pData[i] - pData[i+1]*((0.114*(1-0.114))/(0.436*0.587)) - pData[i+2]*((0.299*(1 - 0.299))/(0.615*0.587));
        m_RGB->imageData[i+2] = pData[i] + pData[i+1]*((1 - 0.114)/0.436);
    

【问题讨论】:

"我目前不知道 YUV 格式" --> ***。阅读它:en.wikipedia.org/wiki/YUV#Conversion_to.2Ffrom_RGB 感谢您链接该文章,但我是否假设我将使用 y、u、v 和 y1 并使用这些变量来生成 RGB 等效项?另外,我是否必须创建 4 个不同的数组来接收每个单独的值集以将它们合并在一起? 您只需要 3 个数组,因为 RGB 中有 3 个颜色分量。但是,是的,您基本上需要单独计算颜色分量并将它们存储在某个地方。 【参考方案1】:

在较新版本的OPENCV 中有一个内置函数可用于将YUV 转换为RGB

cvtColor(src,dst,CV_YUV2BGR_YUY2);

在下划线后指定YUV格式,像这样CV_YUYV2BGR_xxxx

【讨论】:

这只有在 YUV 源是 SD 时才能正常工作。通过基本的视觉检查,它可能看起来正确,但颜色实际上并不正确。这是因为目前用于 YUV 转换的最新 OpenCV 源(2.4.10)仅支持 PAL/NTSC/SECAM 的 601 色彩空间,而不支持 HD 的 709 或 UHD 的 2020。【参考方案2】:

在我看来,您将 YUV422 流解码为 YUV444。尝试对您提供的代码进行此修改:

for(int i = 0, j=0; i < 1280 * 720 * 3; i+=6, j+=4)

    m_RGB->imageData[i] = pData[j] + pData[j+3]*((1 - 0.299)/0.615);
    m_RGB->imageData[i+1] = pData[j] - pData[j+1]*((0.114*(1-0.114))/(0.436*0.587)) - pData[j+3]*((0.299*(1 - 0.299))/(0.615*0.587));
    m_RGB->imageData[i+2] = pData[j] + pData[j+1]*((1 - 0.114)/0.436);
    m_RGB->imageData[i+3] = pData[j+2] + pData[j+3]*((1 - 0.299)/0.615);
    m_RGB->imageData[i+4] = pData[j+2] - pData[j+1]*((0.114*(1-0.114))/(0.436*0.587)) - pData[j+3]*((0.299*(1 - 0.299))/(0.615*0.587));
    m_RGB->imageData[i+5] = pData[j+2] + pData[j+1]*((1 - 0.114)/0.436);

我不确定你的常数是否正确,但最坏的情况是你的颜色会消失 - 图像应该是可识别的。

【讨论】:

您说的常量不正确是对的。我看到了一个漂亮而清晰的图像。我只需要研究 YUV422 常量来纠正这个问题。感谢您的建议。【参考方案3】:

我使用以下 C++ 代码使用 OpenCV 来将 yuv 数据 (YUV_NV21) 转换为 rgb 图像(OpenCV 中的 BGR)

int main()

  const int width  = 1280;
  const int height = 800;

  std::ifstream file_in;
  file_in.open("../image_yuv_nv21_1280_800_01.raw", std::ios::binary);
  std::filebuf *p_filebuf = file_in.rdbuf();
  size_t size = p_filebuf->pubseekoff(0, std::ios::end, std::ios::in);
  p_filebuf->pubseekpos(0, std::ios::in);

  char *buf_src = new char[size];
  p_filebuf->sgetn(buf_src, size);

  cv::Mat mat_src = cv::Mat(height*1.5, width, CV_8UC1, buf_src);
  cv::Mat mat_dst = cv::Mat(height, width, CV_8UC3);

  cv::cvtColor(mat_src, mat_dst, cv::COLOR_YUV2BGR_NV21);
  cv::imwrite("yuv.png", mat_dst);

  file_in.close();
  delete []buf_src;

  return 0;

转换后的结果就像图像yuv.png。

您可以从here 找到测试原始图像,从我的Github Project 找到整个项目

【讨论】:

【参考方案4】:

这可能是错误的道路,但很多人(我的意思是工程师)确实将 YUV 与 YCbCr 混合使用。

尝试

cvCvtColor(src, dsc, CV_YCbCr2RGB) 

或 CV_YCrCb2RGB 或者更奇特的类型。

【讨论】:

我很抱歉它是 CV_YCbCr。 OpenCV 没有 YUV 枚举器。 这只有在 YUV 源是 SD 时才能正常工作。通过基本的视觉检查,它可能看起来正确,但颜色实际上并不正确。这是因为目前用于 YUV 转换的最新 OpenCV 源(2.4.10)仅支持 PAL/NTSC/SECAM 的 601 色彩空间,而不支持 HD 的 709 或 UHD 的 2020。 Opencv 2.4.* 确实有 YUV 枚举器并且没有 CV_YCbCr2RGB。有 CV_YCrCb2RGB 代替。【参考方案5】:

BlackMagic Intensity 软件以 bmdFormat8BitYUV 返回 YUVY' 格式,因此 2 个源像素被压缩为 4 个字节 - 我认为 openCV 的 cvtColor 无法处理。

你可以自己做,也可以直接调用 Intensity 软件的 ConvertFrame() 函数

编辑:Y U V 通常存储为

每个像素都有一个 Y(亮度),但行中的每个交替像素只有一个 U 和 V(颜色)。

所以如果 data 是一个 unsigned char 指向内存的开头,如上所示。

像素 1,Y = 数据[0] U = 数据[+1] V = 数据[+3] 像素 2,Y = 数据[+2] U = 数据[+1] V = 数据[+3]

然后使用您在示例代码中使用的 YUV->RGB 系数。

【讨论】:

我查看了该函数,但它不适用于 IDeckLinkInputFrame 类。最好的方法似乎是我自己做的。感谢您提及 YUVY' 是什么,但是您是否会根据您偶然发现的内容知道转换公式?如果您不知道,请不要竭尽全力帮助我。谢谢 ps 可能弄错了 U/V Cr/Cb - 但应该很明显!【参考方案6】:

也许有人对颜色模型 YCbCr 和 YUV 感到困惑。 Opencv 不处理 YCbCr。取而代之的是 YCrCb,并且它以与 opencv 中的 YUV 相同的方式实现。

来自opencv来源https://github.com/Itseez/opencv/blob/2.4/modules/imgproc/src/color.cpp#L3830:

case CV_BGR2YCrCb: case CV_RGB2YCrCb:
case CV_BGR2YUV: case CV_RGB2YUV:
    // ...
    // 1 if it is BGR, 0 if it is RGB
    bidx = code == CV_BGR2YCrCb || code == CV_BGR2YUV ? 0 : 2; 
    //... converting to YUV with the only difference that brings 
    //    order of Blue and Red channels (variable bidx)

但还有一件事要说。 目前在 OpenCV 分支 2.4.* 中转换 CV_BGR2YUVCV_RGB2YUV 中有一个 bug

目前在实现中使用这个公式:

Y = 0.299B + 0.587G + 0.114R
U = 0.492(R-Y)
V = 0.877(B-Y)

应该是什么(根据wikipedia):

Y = 0.299R + 0.587G + 0.114B
U = 0.492(B-Y)
V = 0.877(R-Y)

红色和蓝色通道在实施的公式中放错了位置。

在错误未修复的情况下转换 BGR->YUV 的可能解决方法:

  cv::Mat source = cv::imread(filename, CV_LOAD_IMAGE_COLOR);
  cv::Mat yuvSource;    
  cvtColor(source, yuvSource, cv::COLOR_BGR2RGB); // rearranges B and R in the appropriate order
  cvtColor(yuvSource, yuvSource, cv::COLOR_BGR2YUV);
  // yuvSource will contain here correct image in YUV color space

【讨论】:

以上是关于在 OpenCV 中将 YUV 转换为 BGR 或 RGB的主要内容,如果未能解决你的问题,请参考以下文章

使用opencv将图像从BGR转换为ARGB

使用 OpenCV 从 android Camera2 将 YUV 转换为 RGB ImageReader 时出现问题,输出图像为灰度

opencv中cvCvtColor能实现yuv到rgb转换吗

rgb 到 yuv 的转换和访问 Y、U 和 V 通道

OpenCV:在 IYUV 中保存视频

使用 OpenCV 将 YUV 转换为有损压缩