Confusión en la conversión de YUV NV21 a RGB

De acuerdo con http://developer.android.com/reference/android/graphics/ImageFormat.html#NV21 , NV21 es el formato predeterminado utilizado.

Hay un buen número de códigos en la web con respecto a la conversión de YUV NV21 a RGB. Sin embargo, cuando reviso el código, dudo sobre la corrección del código.

El primer componente V debe estar primero, seguido por el primer componente U

Según http://wiki.videolan.org/YUV#NV21 , NV21 is like NV12, but with U and V order reversed: it starts with V. Sin embargo, cuando pasé por la implementación del código

  • http://pastebin.com/T0my7zSc – Asume que U es lo primero
  • https://stackoverflow.com/a/8394202/72437 – Asume que U viene primero también
  • https://stackoverflow.com/a/10125048/72437 – Asume que U viene primero también

R debería ser la posición más importante Según la implementación de int argb en Color.java , R suponga que se encuentra en la posición más significativa. Sin embargo, pasé por la siguiente implementación de código

  • http://pastebin.com/T0my7zSc – Supone que R está en la posición menos significativa
  • https://stackoverflow.com/a/8394202/72437 – Asume que R está en la posición menos significativa

Me preguntaba, ¿están cometiendo un error común, o he pasado por alto algo?

Actualmente, mi implementación es la siguiente.

 public static void YUV_NV21_TO_RGB(int[] argb, byte[] yuv, int width, int height) { final int frameSize = width * height; final int ii = 0; final int ij = 0; final int di = +1; final int dj = +1; int a = 0; for (int i = 0, ci = ii; i < height; ++i, ci += di) { for (int j = 0, cj = ij; j > 1) * width + (cj & ~1) + 0])); int u = (0xff & ((int) yuv[frameSize + (ci >> 1) * width + (cj & ~1) + 1])); y = y < 16 ? 16 : y; int r = (int) (1.164f * (y - 16) + 1.596f * (v - 128)); int g = (int) (1.164f * (y - 16) - 0.813f * (v - 128) - 0.391f * (u - 128)); int b = (int) (1.164f * (y - 16) + 2.018f * (u - 128)); r = r  255 ? 255 : r); g = g  255 ? 255 : g); b = b  255 ? 255 : b); argb[a++] = 0xff000000 | (r << 16) | (g << 8) | b; } } } 

Antes que nada, no tengo mucha experiencia con la encoding de imágenes (tiene una exposición limitada a esto hace aproximadamente un año). Entonces, toma mi respuesta con un grano de sal.

Sin embargo, creo que tienes razón. Creo que en su código ambos a) V y U son volteados b) R y B son volteados

Tengo la sensación de que cuando ambas cosas se invierten, producirá el mismo resultado que si no se voltearan. Esa es la razón por la que puede encontrar el código incorrecto en muchos lugares (originalmente, alguien lo entendió mal y después se copió en todos los lugares, porque el código resultante funciona (sin embargo, las variables tienen nombres incorrectos)).

Aquí hay otro ejemplo de código (que funciona igual que el suyo): http://www.41post.com/3470/programming/android-retrieving-the-camera-preview-as-a-pixel-array

Los términos como “posición más importante” son ambiguos, ya que dependen del endian de la máquina.

Cuando todos los tipos de datos son de 8 bits, existe una especificación sencilla y sin ambigüedades: orden de bytes. Por ejemplo, charggba sin signo [4]; tendría los datos almacenados como rgba [0] = r; rgba [1] = g; rgba [2] = b; rgba [3] = a;

o {r, g, b, a} independientemente de la endianidad del procesador.

Si en cambio lo hiciste

int32 color = (r << 24) | (g << 16) | (b << 8) | (a << 0);

obtendrías {r, g, b, a} en un sistema big-endian, y {a, r, g, b} en un sistema little-endian. ¿Trabajas en sistemas que tienen procesadores heterogéneos? Como si tuvieras una CPU y una GPU? ¿Cómo saben qué endian está usando el otro? Está mucho mejor definiendo el orden de bytes.