在OpenCV中将YUV转换为BGR或RGB

时间:2011-10-31 13:30:31

标签: c++ windows opencv video-streaming

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

我目前还没有意识到YUV格式,说实话让我感到困惑,因为它看起来像存储4个频道,但只有3个?我已经从捕获卡中添加了一张图片,希望有人能够理解我可能用来填补空白的内容。

YUV to BGR converted image

Feed通过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);
    }

Attempted RGB conversion

6 个答案:

答案 0 :(得分:8)

在较新版本的OPENCV中,内置函数可用于执行YUVRGB转换

cvtColor(src,dst,CV_YUV2BGR_YUY2);

在下划线后面指定YUV格式,例如CV_YUYV2BGR_xxxx

答案 1 :(得分:5)

在我看来,你正在将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);
}

我不确定你的常数是否正确,但最糟糕的是你的颜色会被关闭 - 图像应该是可识别的。

答案 2 :(得分:2)

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

您可以自己动手,也可以只调用Intensity软件ConvertFrame()函数

编辑:Y U V通常存储为
enter image description here

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

因此,如果数据是指向内存开头的unsigned char,如上所示。

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

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

答案 3 :(得分:1)

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

尝试

cvCvtColor(src, dsc, CV_YCbCr2RGB) 

或CV_YCrCb2RGB或者更奇特的类型。

答案 4 :(得分:1)

也许有人对颜色模型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_BGR2YUV CV_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-&gt; 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

答案 5 :(得分:1)

我使用以下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

中找到整个项目