Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Conversione YUV 4:2:2 a YUV 4:2:0 semiplanar

teoria dei segnali, elaborazione, trasformate Z, Fourier, segnali caratterizzati da processi e variabli aleatorie, stimatori, DSP

Moderatori: Foto Utenteg.schgor, Foto Utentedimaios

0
voti

[1] Conversione YUV 4:2:2 a YUV 4:2:0 semiplanar

Messaggioda Foto Utentegvee » 24 giu 2018, 19:38

Un saluto a tutti O_/

Ho bisogno di effettuare una conversione di rappresentazione pixel da YUV 4:2:2 a YUV 4:2:0 (NV12) semiplanar, ma nonostante le descrizioni riportate ai seguenti link (quelli delle API v4l2 sono più dettagliati)

http://www.fourcc.org/pixel-format/yuv-yuy2/
https://linuxtv.org/downloads/v4l-dvb-a ... -yuyv.html

http://www.fourcc.org/pixel-format/yuv-nv12/
https://linuxtv.org/downloads/v4l-dvb-a ... -nv12.html

non riesco ad ottenere un frame convertito correttamente.
Osservando i due layout del YUV 4:2:2 e YUV 4:2:0, intuisco che le componenti di luminosità Y si copiano tutte senza downsampling mentre le componenti di colore sono alternate e con downsampling.

Per provare la conversione del frame in allegato (racchiuso in file zip) ho scritto questo codice:

frame-1.zip
frame YUV 4:2:2
(297.29 KiB) Scaricato 7 volte


Codice: Seleziona tutto
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void YUV422ToYUV420sp(uint8_t *yuv422, uint32_t yuv422Size, uint8_t *yuv420, uint32_t yuv420Size)
{
    const uint32_t ysize = yuv422Size / 2;
    // YUV 4:2:2 size is width * height * 2
    //
    // YUV 4:2:0 size is width * height * 3/2
    // where Y size is width * height
    // and UV size is (width * height)/2
    uint8_t *py422 = yuv422;
    uint8_t *py420 = yuv420;
    uint8_t *puv420 = yuv420 + ysize;

    uint32_t uvIndex = 0;
    for(uint32_t i = 0; i < yuv422Size; i += 4)
    {
        *py420 = yuv422[i];
        py420++;
       
        if(uvIndex < (ysize / 2))
        {
            *puv420 = yuv422[i + 1];
            puv420++;

            uvIndex++;
        }

        *py420 = yuv422[i + 2];
        py420++;
       
        if(uvIndex < (ysize / 2))
        {
            *puv420 = yuv422[i + 3];
            puv420++;

            uvIndex++;
        }
    }
}

int main(int argc, char *argv[])
{
    // size of frame to test is 640 * 480
    uint32_t yuv422Size = 640 * 480 * 2;
    uint8_t yuv422data[yuv422Size];
    uint32_t yuv420Size = 640 * 480 * 3/2;
    uint8_t yuv420data[yuv420Size];
   
    int fd = open(argv[1], O_RDWR);
    if(fd > 0)
    {
        read(fd, yuv422data, yuv422Size);
        close(fd);
    }
    else
    {
        perror("read: ");
        return 1;
    }

    YUV422ToYUV420sp(yuv422data, yuv422Size, yuv420data, yuv420Size);
    fd = open("toYUV420.raw", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    if(fd > 0)
    {
        write(fd, yuv420data, yuv420Size);
        close(fd);
    }
    else
    {
        perror("write: ");
        return 1;
    }
   
    return 0;
}


pero evidentemente c'è qualcosa che non mi è chiaro perché la conversione corretta dovrebbe portare al seguente risultatato dovrebbe essere questo:

image.jpg


mentre la conversione applicata secondo quanto intuisco restituisce il seguente risultato:

image_noOK.jpg


in cui si può vedere che la componente di colore è sfasata (o almeno è quello che sembra).. :-|

Sono sicuro del formato di origine YUV 4:2:2 anche perché ho implementato la conversione YUV 4:2:2 a RGB (planar e packed) con successo.
Per visualizzare i frame YUV 4:2:2 e YUV 4:2:0 io uso http://rawpixels.net/

Per YUV 4:2:2 le opzioni sono:
Predefined format: YUY2
Pixel Format: YUV
Pixel Plane: PackedYUV

Per YUV 4:2:0 le opzioni sono:
Predefined format: YUV 420 SP
Pixel Format: YUV
Pixel Plane: Semiplanar

mentre le immagini in allegato le ho convertite a JPG dato che occupano di meno rispetto alla compressione PNG.

Qualcono ha esperienza con questo tipo di conversioni e magari ha una interpretazione alternativa e corretta rispetto a quella che ho io del formato YUV 4:2:0 ? Perché dopo varie supposizioni e prove non capisco dove sbaglio.

Ringrazio in anticipo.

O_/
Avatar utente
Foto Utentegvee
265 1 5
Frequentatore
Frequentatore
 
Messaggi: 104
Iscritto il: 11 feb 2018, 20:34

1
voti

[2] Re: Conversione YUV 4:2:2 a YUV 4:2:0 semiplanar

Messaggioda Foto Utentegvee » 2 lug 2018, 9:26

Dunque alla fine ho risolto:

Codice: Seleziona tutto
void YUV422ToYUV420sp(uint8_t *yuv422, uint8_t *yuv420, uint32_t width, uint32_t height)
{
    uint8_t *psrc = yuv422;
    // pointer to Y plane
    uint8_t *py420 = yuv420;
    // pointer to UV plane
    uint8_t *puv420 = yuv420 + (width * height);

    for(uint32_t y = 0; y < height; y++)
    {
        for(uint32_t x = 0; x < width/2; x++)
        {
            *py420 = psrc[0];
            py420++;
            *py420 = psrc[2];
            py420++;

            if(!(y % 2))
            {
                *puv420 = psrc[1];
                puv420++;

                *puv420 = psrc[3];
                puv420++;
            }

            psrc+=4;
        }
    }
}


Avevo bisogno di qualche giorno di riposo...
Ne approfitto per una cartolina.

IMG_20180627_165040.jpg


O_/
Avatar utente
Foto Utentegvee
265 1 5
Frequentatore
Frequentatore
 
Messaggi: 104
Iscritto il: 11 feb 2018, 20:34


Torna a Elaborazione numerica ed analogica dei segnali

Chi c’è in linea

Visitano il forum: Nessuno e 1 ospite