Domanda

Quando si dimezzano la larghezza e/o l'altezza dei canali Chroma, qual è il modo corretto di sottocampilare? Per prendere un pixel Chroma per ogni pixel Luma 2x2, quando si campionano da una fonte Chroma a risoluzione a risoluzione, quale pixel Chroma prendiamo - in alto a sinistra? Media di tutti e 4? Non importa?

Questo è il mio codice attuale

if field == 'top':
    i = 0
elif field == 'bottom':
    i = 1

U = fromstring(Udata, dtype='uint8', count=w/2*h).reshape(h,w/2)

# halve chroma height (it's already half-width from UYVY source) by line skipping
U = U[i::2]

# scale chroma by a factor of 0.5 (2x2 pixels in -> 1 pixel out)
U = (U[0::2, 0::2]>>2) + (U[0::2, 1::2]>>2) + (U[1::2, 0::2]>>2) + (U[1::2, 1::2]>>2) + \
  (((U[0::2, 0::2]%4)  + (U[0::2, 1::2]%4)  + (U[1::2, 0::2]%4)  + (U[1::2, 1::2]%4)) >> 2)
È stato utile?

Soluzione

Ideale, interpoleresti i dati per produrre la migliore immagine possibile, tuttavia penso che la tua domanda sia meglio rispondere con una rapida panoramica di dove si trovano i campioni Luma e Chrom (immagina una fotocamera con una griglia per luma nad per l'altra) . Per il sottocampionamento esistono più standard per la selezione della posizione di Chroma Relitve ai campioni di luma.

La maggior parte del croma è co-localizzato con il pixel Luma "in alto a sinistra",

XO  X   XO  X

X   X   X   X

XO  X   XO  X

X   X   X   X

o si trova al centro della piazza,

X   X   X   X
  O      O
X   X   X   X

X   X   X   X
  O      O
X   X   X   X

o si trova sul lato sinistro del quadrato tra i due campioni di luma sinistro.

X   X   X   X
O       O
X   X   X   X

X   X   X   X
O       O
X   X   X   X

Si noti che in tutti i casi il valore Chroma co-localizzato con almeno alcuni campioni di Luma sarà una combinazione di diversi valori di Chroma, questo viene generalmente fatto con un filtro FIR, motivo per cui un altro filtro viene raccomandato per l'opperazione inversa (tuttavia è possibile Ottieni risultati OK con la media)

Altri suggerimenti

Il modo corretto per convertire da YUV 4: 2: 0 a Yuv 4: 2: 2 è utilizzare un filtro a schiera a 6 tap.

L'SRC per questo deriva dall'implementazione di riferimento di MPEG2 che puoi trovare qui http://www.mpeg.org/mpeg/video/mmsg-free-mpeg-software.html

Scegli il file "MPEGV12.ZIP"

Implementazione in C:

/* vertical 1:2 interpolation filter */
static void conv420to422(unsigned char* src, unsigned char* dst)
{
  int w, h, i, j, j2;
  int jm6, jm5, jm4, jm3, jm2, jm1, jp1, jp2, jp3, jp4, jp5, jp6, jp7;

  w = 352>>1;
  h = 288>>1;

  printf("hello \n");

  if (1)
  {
    /* intra frame */
    for (i=0; i<w; i++)
    {
      for (j=0; j<h; j++)
      {
    //printf("%d,%d\n", i, j);
        j2 = j<<1;
        jm3 = (j<3) ? 0 : j-3;
        jm2 = (j<2) ? 0 : j-2;
        jm1 = (j<1) ? 0 : j-1;
        jp1 = (j<h-1) ? j+1 : h-1;
        jp2 = (j<h-2) ? j+2 : h-1;
        jp3 = (j<h-3) ? j+3 : h-1;

        /* FIR filter coefficients (*256): 5 -21 70 228 -37 11 */
        /* New FIR filter coefficients (*256): 3 -16 67 227 -32 7 */
        dst[w*j2] =     Clip[(int)(  3*src[w*jm3]
                             -16*src[w*jm2]
                             +67*src[w*jm1]
                            +227*src[w*j]
                             -32*src[w*jp1]
                             +7*src[w*jp2]+128)>>8];

        dst[w*(j2+1)] = Clip[(int)(  3*src[w*jp3]
                             -16*src[w*jp2]
                             +67*src[w*jp1]
                            +227*src[w*j]
                             -32*src[w*jm1]
                             +7*src[w*jm2]+128)>>8];
      }
      src++;
      dst++;
    }
  }
  else
  {
    /* intra field */
    for (i=0; i<w; i++)
    {
      for (j=0; j<h; j+=2)
      {
        j2 = j<<1;

        /* top field */
        jm6 = (j<6) ? 0 : j-6;
        jm4 = (j<4) ? 0 : j-4;
        jm2 = (j<2) ? 0 : j-2;
        jp2 = (j<h-2) ? j+2 : h-2;
        jp4 = (j<h-4) ? j+4 : h-2;
        jp6 = (j<h-6) ? j+6 : h-2;

        /* Polyphase FIR filter coefficients (*256): 2 -10 35 242 -18 5 */
        /* New polyphase FIR filter coefficients (*256): 1 -7 30 248 -21 5 */
        dst[w*j2] = Clip[(int)(  1*src[w*jm6]
                         -7*src[w*jm4]
                         +30*src[w*jm2]
                        +248*src[w*j]
                         -21*src[w*jp2]
                          +5*src[w*jp4]+128)>>8];

        /* Polyphase FIR filter coefficients (*256): 11 -38 192 113 -30 8 */
        /* New polyphase FIR filter coefficients (*256):7 -35 194 110 -24 4 */
        dst[w*(j2+2)] = Clip[(int)( 7*src[w*jm4]
                             -35*src[w*jm2]
                            +194*src[w*j]
                            +110*src[w*jp2]
                             -24*src[w*jp4]
                              +4*src[w*jp6]+128)>>8];

        /* bottom field */
        jm5 = (j<5) ? 1 : j-5;
        jm3 = (j<3) ? 1 : j-3;
        jm1 = (j<1) ? 1 : j-1;
        jp1 = (j<h-1) ? j+1 : h-1;
        jp3 = (j<h-3) ? j+3 : h-1;
        jp5 = (j<h-5) ? j+5 : h-1;
        jp7 = (j<h-7) ? j+7 : h-1;

        /* Polyphase FIR filter coefficients (*256): 11 -38 192 113 -30 8 */
        /* New polyphase FIR filter coefficients (*256):7 -35 194 110 -24 4 */
        dst[w*(j2+1)] = Clip[(int)( 7*src[w*jp5]
                             -35*src[w*jp3]
                            +194*src[w*jp1]
                            +110*src[w*jm1]
                             -24*src[w*jm3]
                              +4*src[w*jm5]+128)>>8];

        dst[w*(j2+3)] = Clip[(int)(  1*src[w*jp7]
                             -7*src[w*jp5]
                             +30*src[w*jp3]
                            +248*src[w*jp1]
                             -21*src[w*jm1]
                              +5*src[w*jm3]+128)>>8];
      }
      src++;
      dst++;
    }
  }
}

E in Python:

def conv420to422(src, dst):
    """420 to 422 - vertical 1:2 interpolation filter """

    width = 352                  # 352
    height = 288                 # 288
    w = width >> 1               # 176
    h = height >> 1              # 144

    n = 0
    k = 0
    for i in range(0, w):
        for j in range(0, h):
            j2 = j<<1
            jm3 = 0 if (j < 3) else j - 3
            jm2 = 0 if (j < 2) else j - 2
            jm1 = 0 if (j < 1) else j - 1
            jp1 = j + 1 if (j < h - 1) else h - 1
            jp2 = j + 2 if (j < h - 2) else h - 1
            jp3 = j + 3 if (j < h - 3) else h - 1

            a = (3*src[n+w*jm3]-16*src[n+w*jm2]+67*src[n+w*jm1]+227*src[n+w*j]-32*src[n+w*jp1]+7*src[n+w*jp2]+128)>>8
            dst[k+w*j2] = clip(a)
            b = (3*src[n+w*jp3]-16*src[n+w*jp2]+67*src[n+w*jp1]+227*src[n+w*j]-32*src[n+w*jm1]+7*src[n+w*jm2]+128)>>8
            dst[k+w*(j2+1)] = clip(b)
        n += 1
        k += 1
    return dst
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top