如何在C++中将YUY2转换为位图

7
我正在使用一个安全摄像头DLL来检索图像。 DLL调用我的程序的函数,并将图像缓冲区作为参数传递,但是图像以yuy2格式存在。 我需要将此缓冲区转换为RGB,但是我尝试了互联网上找到的每个公式,都没有成功。 我尝试了每个示例(包括http://msdn.microsoft.com/en-us/library/aa904813(VS.80).aspx#yuvformats_2),但结果都是错误的颜色。 我能够仅使用像素的Y分量将缓冲区转换为BW图像,但我确实需要彩色图片。 我调试了(仅汇编)显示屏幕中图像的DLL,它使用DirectDraw来完成此操作。

我只是猜测 -> 这不是比特顺序问题的例子吗? - nothrow
2
对于像我一样感到困惑的人。YUY2是一种宏像素格式,其形式为Y0 | U0 | Y1 | V0。每4个字节表示两个RGB像素。 Y称为亮度(Luma),U称为蓝色色差(Cb),V称为红色色差(Cr)。 - Maghoumi
4个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
13

根据问题中的Microsoft链接提供的信息:

for (int i = 0;  i < width/2;  ++i)
{
    int y0 = ptrIn[0];
    int u0 = ptrIn[1];
    int y1 = ptrIn[2];
    int v0 = ptrIn[3];
    ptrIn += 4;
    int c = y0 - 16;
    int d = u0 - 128;
    int e = v0 - 128;
    ptrOut[0] = clip(( 298 * c + 516 * d + 128) >> 8); // blue
    ptrOut[1] = clip(( 298 * c - 100 * d - 208 * e + 128) >> 8); // green
    ptrOut[2] = clip(( 298 * c + 409 * e + 128) >> 8); // red
    c = y1 - 16;
    ptrOut[3] = clip(( 298 * c + 516 * d + 128) >> 8); // blue
    ptrOut[4] = clip(( 298 * c - 100 * d - 208 * e + 128) >> 8); // green
    ptrOut[5] = clip(( 298 * c + 409 * e + 128) >> 8); // red
    ptrOut += 6;
}

嗨,我对这个话题还很陌生,你如何声明输出缓冲区,并将其保存到文件中?你已经得到了我的投票。谢谢。 - Delta
@Delta, 你可以使用 vector,例如 vector<unsigned char> buffer(width*height*3); ptrOut = &buffer[0];。至于如何保存到文件,已经在其他地方得到了回答,例如:https://dev59.com/YHE85IYBdhLWcg3wr1ux - Mark Ransom
为什么要除以256(>> 8),而不是255?这个输出是否归一化到[0,1]或[0,255]? - PixelArtDragon
@PixelArtDragon,我写这个已经有很长时间了,请原谅我记不太清楚。我几乎可以确定是指[0, 255],因为这在RGB中99%的情况下都是使用的。现在对我来说很难将这个答案与源材料联系起来,可能是参考资料多年来发生了变化。 - Mark Ransom

3
这个公式是有效的:
int C = luma - 16;
int D = cr - 128;
int E = cb - 128;
r = (298*C+409*E+128)/256;
g = (298*C-100*D-208*E+128)/256;
b = (298*C+516*D+128)/256;

我从Matlab的一个例子中得到了这个。

需要注意的是:在内存中,Windows位图不是RGB格式,而是BGR格式。如果您要写入内存缓冲区,您需要进行如下操作:

rgbbuffer[rgbindex] = (char)b;
rgbbuffer[rgbindex + 1] = (char)g;
rgbbuffer[rgbindex + 2] = (char)r;

我的答案对于BGR的顺序是正确的,可以看代码注释。很抱歉我没有明确指出这一点。对于那些使用Windows位图的人来说,这总是第一个需要注意的问题,第二个则是行是倒过来的。 - Mark Ransom

1
如果您已经在使用DirectShow从安全摄像机中获取视频数据,那么您可以简单地将“颜色空间转换滤镜”添加到您的DirectShow图形中。但是,如果您还没有使用DirectShow(听起来好像不是),那么使用Daniel链接的公式自己将数据转换为RGB会更加简单。将DirectShow添加到项目中非常复杂。

2
如果您打开链接,您会发现此过滤器仅适用于RGB。 - Dee Mon
是的,颜色空间转换滤镜只能进行 RGB -> RGB 转换。 - user206705

0

你需要编写自己的转换器。GDI+不知道如何处理YUY2位图。

这里查看。

请注意,两个像素共享相同的颜色值,但具有不同的亮度值。

这里提供了一些公式,以帮助您编写转换器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,