2011-11-07 18 views
5

He estado tratando de hacer frente a un YUV422 en un problema de conversión RGB durante aproximadamente una semana. He visitado muchos sitios web diferentes y he obtenido diferentes fórmulas de cada uno. Si alguien más tiene alguna sugerencia, me alegraría saber de ellos. Las siguientes fórmulas me brindan una imagen con una tonalidad púrpura o verde o una tonalidad verde. A partir de este momento, no he podido encontrar una fórmula que me permita recuperar una imagen RGB adecuada. He incluido todos mis diversos fragmentos de código a continuación.Conversión correcta de YUV422 a 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));*/ 
    } 

Cualquier ayuda es muy apreciada.

+1

¿Cuál es la fuente de los datos YUV, y lo que es el destino? Por ejemplo, si el destino es Windows, debe usar el orden BGR en lugar de RGB. –

+0

el YUV proviene de una tarjeta de captura Decklink Intensity Pro. También traté de voltear los valores BGR/RGB y no ayudó. Esto se está haciendo en un cuadro de Windows – Seb

+0

Si está utilizando el SDK de mazo, ¿por qué no usa simplemente el método ConvertFrame que es parte de la API? – ronag

Respuesta

5

Algunas pistas para ayudarle a lo largo de:

Usted está confundiendo con Cr Cb.

Suponiendo UYVY/422

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

su cálculo de conversión son extraño, e incorrecta de alta definición.

para 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))); 

para 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))); 

Simplemente podría utilizar ConvertFrame que es una parte del SDK Decklink.

+0

gracias porque tu respuesta me ha ayudado. Preguntas: ¿HD significa 1280x720 o 1920x1080? ¿Qué hay de 4k? ¡Por el orden Y1CrY2Cb funcionó para mí con yuy2! aunque basado en msdn Cb es 'u' y se suponía que era Y1CbY2Cr pero haciendo eso ¡muestra azul en lugar de rojo! ¿Puedes explicar por qué la orden se tuerce? o ¿msdn Cb = 'u' no es válido? 1 –

1

Suponiendo que esté lleno 422, no veo que ninguno de sus bloques muestree los datos de entrada correctamente. En el paquete 422 los datos de entrada irán a Y1U1Y2V1 Y3U2Y4V2 donde la imagen general es una imagen Y (luma) a resolución completa y una cada U y V cada una a la mitad de la resolución horizontal.

Aquí es donde me gustaría empezar: Descomprimir los valores alternativos de la entrada y de una imagen en escala de grises:

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]; 
} 

Una vez que tenga que sintoniza para producir una imagen en escala de grises a continuación, introducir U y V examinado pData[j+1] y pData[j+3] (o, en píxeles pares, pData[j-1] y pData[j+1]). Simplificando eso es por qué algunos algoritmos hacen dos píxeles YUV a la vez.

Cuando que funciona, considere extraer las imágenes U y V y remámelas adecuadamente a resolución completa para producir una imagen 444. Simplemente duplicar U y V para píxeles adyacentes es como subir de escala mediante la duplicación de píxeles.

(Tenga en cuenta que otros arreglos como 420 tienen aún más complicado co-localización)

+0

Esto me dio una imagen en escala de grises, pero todo parece como si se le aplicara una imagen borrosa gaussiana. – Seb

0

también tuve problemas con la conversión

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

u y v son sbyte y y es sólo un byte.

+0

¿Estás diciendo que esta es la conversión correcta o que te costó intentar usar esta conversión? –

+0

Esta fue la versión correcta –

3

Su problema es que hay muchos formatos de YUV422 por ahí. Debe encontrar el exacto (el índice FOURCC para el video específico que está usando), y luego descubrir la forma correcta de decodificarlo.

Lo que puede hacer es guardar un video de su placa, ábralo en VLC, y mire los detalles del códec para encontrar el FOURCC exacto usado.

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

Cuestiones relacionadas