在 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_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->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 从 android Camera2 将 YUV 转换为 RGB ImageReader 时出现问题,输出图像为灰度