更正YUV422到RGB的转换

时间:2011-11-07 21:02:32

标签: c++ image-processing opencv rgb yuv

我一直试图将YUV422解决为RGB转换问题大约一周。我访问过很多不同的网站,每个网站都有不同的公式。如果其他人有任何建议我会很高兴听到他们。下面的公式给我一个图像,其中包含整体紫色或绿色色调。到目前为止,我还没有找到一个允许我回到正确的RGB图像的公式。我在下面列出了我所有的各种代码。

    //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);*/

    //  m_RGB->imageData[i] = pData[i] + 1.403 * (pData[i+1] - 128);
    //  m_RGB->imageData[i+1] = pData[i] + 0.344 * (pData[i+1] - 128) - 0.714 * (pData[i+2] - 128);
    //  m_RGB->imageData[i+2] = pData[i] + 1.773 * (pData[i+2] - 128);
    //}

    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);*/

        /*m_RGB->imageData[i] = pData[j] + 1.403 * (pData[j+3] - 128);
        m_RGB->imageData[i+1] = pData[j] + 0.344 * (pData[j+1] - 128) - 0.714 * (pData[j+3] - 128);
        m_RGB->imageData[i+2] = pData[j] + 1.773 * (pData[j+1] - 128);
        m_RGB->imageData[i+3] = pData[j+2] + 1.403 * (pData[j+3] - 128);
        m_RGB->imageData[i+4] = pData[j+2] + 0.344 * (pData[j+1] - 128) - 0.714 * (pData[j+3] - 128);
        m_RGB->imageData[i+5] = pData[j+2] + 1.773 * (pData[j+1] - 128);*/

        BYTE Cr = pData[j+3] - 128;
        BYTE Cb = pData[j+1] - 128;
        /*m_RGB->imageData[i] = pData[j] + Cr + (Cr >> 2) + (Cr >> 3) + (Cr >> 5);
        m_RGB->imageData[i+1] = pData[j] - ((Cb >> 2) + (Cb >> 4) + (Cb >> 5)) - ((Cr >> 1) + (Cr >> 3) + (Cr >> 4) + (Cr >> 5));
        m_RGB->imageData[i+2] = pData[j] + Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6);
        m_RGB->imageData[i+3] = pData[j+2] + Cr + (Cr >> 2) + (Cr >> 3) + (Cr >> 5);
        m_RGB->imageData[i+4] = pData[j+2] - ((Cb >> 2) + (Cb >> 4) + (Cb >> 5)) - ((Cr >> 1) + (Cr >> 3) + (Cr >> 4) + (Cr >> 5));
        m_RGB->imageData[i+5] = pData[j+2] + Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6);*/

        /*int R1 = clamp(1 * pData[j] + 0 * Cb + 1.4 * Cr, 0, 255), R2 = clamp(1 * pData[j+2] + 0 * Cb + 1.4 * Cr, 0, 255);
        int G1 = clamp(1 * pData[j] - 0.343 * Cb - 0.711 * Cr, 0, 255), G2 = clamp(1 * pData[j+2] - 0.343 * Cb - 0.711 * Cr, 0, 255);
        int B1 = clamp(1 * pData[j] + 1.765 * Cb + 0 * Cr, 0, 255), B2 = clamp(1 * pData[j+2] + 1.765 * Cb + 0 * Cr, 0, 255);*/

        /*int R1 = clamp(pData[j] + 1.403 * (pData[j+3] - 128), 0, 255), R2 = clamp(pData[j+2] + 1.403 * (pData[j+3] - 128), 0, 255);
        int G1 = clamp(pData[j] + 0.344 * (pData[j+1] - 128) - 0.714 * (pData[j+3] - 128), 0, 255), G2 = clamp(pData[j+2] + 0.344 * (pData[j+1] - 128) - 0.714 * (pData[j+3] - 128), 0, 255);
        int B1 = clamp(pData[j] + 1.773 * (pData[j+1] - 128), 0, 255), B2 = clamp(pData[j+2] + 1.773 * (pData[j+1] - 128), 0, 255);*/

        int R1 = clamp((298 * (pData[j] - 16) + 409 * (pData[j+3] - 128) + 128) >> 8, 0, 255), R2 = clamp((298 * (pData[j+2] - 16) + 409 * (pData[j+3] - 128) + 128) >> 8, 0, 255);
        int G1 = clamp((298 * (pData[j] - 16) - 100 * (pData[j+1] - 128) - 208 * (pData[j+3] - 128) + 128) >> 8, 0, 255), G2 = clamp((298 * (pData[j+2] - 16) - 100 * (pData[j+1] - 128) - 208 * (pData[j+3] - 128) + 128) >> 8, 0, 255);
        int B1 = clamp((298 * (pData[j] - 16) + 516 * (pData[j+1] - 128) + 128) >> 8, 0, 255), B2 = clamp((298 * (pData[j+2] - 16) + 516 * (pData[j+1] - 128) + 128) >> 8, 0, 255);

        //printf("R: %d, G: %d, B: %d, R': %d, G': %d, B': %d \n", R1, G1, B1, R2, G2, B2);

        m_RGB->imageData[i] = (char)R1;
        m_RGB->imageData[i+1] = (char)G1;
        m_RGB->imageData[i+2] = (char)B1;
        m_RGB->imageData[i+3] = (char)R2;
        m_RGB->imageData[i+4] = (char)G2;
        m_RGB->imageData[i+5] = (char)B2;

        /*m_RGB->imageData[i] = (char)(clamp(1.164 * (pData[j] - 16) + 1.793 * (Cr), 0, 255));
        m_RGB->imageData[i+1] = (char)(clamp(1.164 * (pData[j] - 16) - 0.534 * (Cr) - 0.213 * (Cb), 0, 255));
        m_RGB->imageData[i+2] = (char)(clamp(1.164 * (pData[j] - 16) + 2.115 * (Cb), 0, 255));
        m_RGB->imageData[i+3] = (char)(clamp(1.164 * (pData[j+2] - 16) + 1.793 * (Cr), 0, 255));
        m_RGB->imageData[i+4] = (char)(clamp(1.164 * (pData[j+2] - 16) - 0.534 * (Cr) - 0.213 * (Cb), 0, 255));
        m_RGB->imageData[i+5] = (char)(clamp(1.164 * (pData[j+2] - 16) + 2.115 * (Cb), 0, 255));*/
    }

非常感谢任何帮助。

4 个答案:

答案 0 :(得分:5)

一些帮助你的线索:

你把Cr与Cb混淆。

假设UYVY / 422

Y1 = data[j+0];
Cr = data[j+1];
Y2 = data[j+2];
Cb = data[j+3];

您的转化计算很奇怪,而且HD不正确。

对于SD

R = max(0, min(255, 1.164(Y - 16) + 1.596(Cr - 128)));
G = max(0, min(255, 1.164(Y - 16) - 0.813(Cr - 128) - 0.391(Cb - 128)));
B = max(0, min(255, 1.164(Y - 16) + 2.018(Cr - 128)));

对于HD

R = max(0, min(255, 1.164(Y - 16) + 1.793(Cr - 128)));
G = max(0, min(255, 1.164(Y - 16) - 0.534(Cr - 128) - 0.213(Cb - 128)));
B = max(0, min(255, 1.164(Y - 16) + 2.115(Cr - 128)));

您可以简单地使用ConvertFrame,这是Decklink SDK的一部分。

答案 1 :(得分:3)

你的问题是有很多YUV422格式。您必须找到确切的一个(您正在使用的特定视频的FOURCC索引),然后找出解码它的正确方法。

您可以做的是从您的电路板保存一些视频,在VLC中打开它,并查看编解码器详细信息以找到所使用的确切FOURCC。

http://www.fourcc.org/yuv.php

答案 2 :(得分:1)

假设打包422我没有看到任何块正确地对输入数据进行采样。在打包422中,输入数据将为Y1U1Y2V1 Y3U2Y4V2,其中整个图像为全分辨率的Y(亮度)图像,U和V各为半水平分辨率。

这是我要开始的地方:解压缩输入的交替值并提取灰度图像:

for (uint i = 0, j = 0; i < 1280 * 720 * 3; i += 3, j += 2) {
    m_RGB->imageData[i] = pData[j];
    m_RGB->imageData[i+1] = pData[j];
    m_RGB->imageData[i+2] = pData[j];
}

调整后可以生成灰度图像,然后通过查看pData[j+1]pData[j+3](或偶数像素,pData[j-1]pData[j+1]来引入U和V. )。简化这就是为什么有些算法一次做两个YUV像素的原因。

工作时,请考虑提取U和V图像并将其正确地重新采样到全分辨率以生成444图像。简单地为相邻像素复制U和V就像通过复制像素一样进行放大。

(请注意,像420这样的其他安排有更复杂的共址)

答案 3 :(得分:0)

我也在努力进行转换

// Get the bytes
var u = bytes[0]; 
var y1 = bytes[1];
var v = bytes[2];
var y2 = bytes[3];

// Convert, cast to signed byte is important!
var r = y + (1.403 * (sbyte)v);
var g = y - (0.344 * (sbyte)u) - (0.714 * (sbyte)v);
var b = y + (1.770 * (sbyte)u);

if (r < 0)
    r = 0;
else if (r > 255)
    r = 255;

if (g < 0)
    g = 0;
else if (g > 255)
    g = 255;

if (b < 0)
    b = 0;
else if (b > 255)
    b = 255;

return Color.FromArgb((byte)r, (byte)g, (byte)b);

uvsbyte,而y只是byte