2011-11-07 16 views
5

Ho cercato di affrontare un problema di conversione RGB su un YUV422 per circa una settimana. Ho visitato molti siti Web diversi e ho ricevuto formule diverse da ognuno di essi. Se qualcun altro ha qualche suggerimento sarei felice di sentirmi parlare di loro. Le formule qui sotto mi danno un'immagine con entrambi e in viola o con una tonalità verde. A partire da questo momento non sono stato in grado di trovare una formula che mi permetta di recuperare un'immagine RGB appropriata. Ho incluso tutti i miei vari pezzi di codice qui sotto.Corretta conversione da 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));*/ 
    } 

Qualsiasi aiuto è molto apprezzato.

+1

Qual è la fonte dei dati YUV, e qual è la destinazione? Ad esempio se la destinazione è Windows è necessario utilizzare l'ordine BGR piuttosto che RGB. –

+0

YUV proviene da una scheda di acquisizione Decklink Intensity Pro. Ho anche provato a capovolgere i valori BGR/RGB e non ha aiutato. Questo viene fatto su una casella di Windows – Seb

+0

Se stai usando l'SDK di ponte, perché non usi semplicemente il metodo ConvertFrame che fa parte dell'API? – ronag

risposta

5

Alcuni indizi per aiutarti a lungo:

Stai confondendo Credito con Cb.

Supponendo UYVY/422

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

tuo calcolo di conversione sono strano, e non corretta per HD.

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

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

Si potrebbe semplicemente utilizzare ConvertFrame che è una parte della Decklink SDK.

+0

grazie perché la tua risposta mi ha aiutato. Domande: HD significa 1280x720 o 1920x1080? che dire di 4k? secondo l'ordine Y1CrY2Cb ha funzionato per me con yuy2! anche se basato su msdn Cb è 'u' e doveva essere Y1CbY2Cr ma facendo ciò mostra il blu al posto del rosso! puoi spiegare perché l'ordine è stato distorto? o msdn Cb = 'u' non valido? 1 –

1

Supponendo imballato 422 Non vedo nessuno dei vostri blocchi campionare correttamente i dati di input. Nel pacchetto 422 i dati di input andranno a Y1U1Y2V1 Y3U2Y4V2 dove l'immagine complessiva è un'immagine Y (luma) a piena risoluzione e uno ciascuno di U e V ciascuno a metà risoluzione orizzontale.

Ecco dove vorrei iniziare: Estrarre valori alternati di ingresso e estrarre un'immagine in scala di grigi:

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 volta che avete sintonizzato per produrre un'immagine in scala di grigi poi introdurre U e V, cercando in pData[j+1] e pData[j+3] (o, anche su pixel, pData[j-1] e pData[j+1]). Semplificando è per questo che alcuni algoritmi fanno due pixel YUV alla volta.

Quando che funziona, prendere in considerazione l'estrazione delle immagini U e V e il loro corretto ricampionamento alla massima risoluzione per produrre un'immagine 444. La semplice duplicazione di U e V per pixel adiacenti è come l'upscaling duplicando i pixel.

(Si noti che le altre disposizioni, come 420 sono ancora più complicate co-siting)

+0

Questo mi ha ottenuto un'immagine in scala di grigi, ma tutto sembra come se vi fosse applicata una sfocatura gaussiana. – Seb

0

Ho anche lottato con la conversione

// 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 e v sono sbyte, e y è solo un byte.

+0

Stai dicendo che questa è la conversione corretta o che hai faticato a provare a utilizzare questa conversione? –

+0

Questa era la versione corretta –

3

Il tuo problema è che ci sono molti formati di YUV422 là fuori. Devi trovare l'esatto (l'indice FOURCC per il video specifico che stai utilizzando), e quindi trovare il modo corretto per decodificarlo.

Quello che puoi fare è salvare un po 'di video dalla tua scheda, aprirlo in VLC e guardare i dettagli del codec per trovare l'esatto FOURCC usato.

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