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

Según http://developer.android.com/reference/android/graphics/ImageFormat.html#NV21 , NV21 es el formato usado por defecto.

Hay una gran cantidad de código en la web con respecto a la conversión YUV NV21 a RGB. Sin embargo, cuando reviso el código, dudo de la corrección del código.

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

De acuerdo con 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 viene primero
  • Https://stackoverflow.com/a/8394202/72437 – asume que U viene primero también
  • Https://stackoverflow.com/a/10125048/72437 – Ases U viene primero también

R debe ser la posición más significativa. Según la implementación de int argb en Color.java , R supone estar en la posición más significativa. Sin embargo, pasé por la implementación de código siguiente

  • Http://pastebin.com/T0my7zSc – Asume 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 < width; ++j, cj += dj) { int y = (0xff & ((int) yuv[ci * width + cj])); int v = (0xff & ((int) yuv[frameSize + (ci >> 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 < 0 ? 0 : (r > 255 ? 255 : r); g = g < 0 ? 0 : (g > 255 ? 255 : g); b = b < 0 ? 0 : (b > 255 ? 255 : b); argb[a++] = 0xff000000 | (r << 16) | (g << 8) | b; } } } 

En primer lugar, no soy super experimentado con la codificación de imágenes (tiene una exposición limitada a esto hace aproximadamente un año). Por lo tanto, tomar mi respuesta con grano de sal.

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

Tengo la sensación de que cuando ambas cosas son volteadas, producirá el mismo resultado que si no fueran volteadas. Esa es la razón por la que se puede encontrar código incorrecto en muchos lugares (originalmente, alguien se equivocó y después de que se copió en todos los lugares, porque el código resultante funciona (sin embargo, las variables denominadas incorrectamente)).

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

Términos como "posición más significativa" son ambiguos, porque depende del endian de la máquina.

Cuando todos los tipos de datos son 8 bits, hay una especificación sencilla sin ambigüedad: orden de bytes. Por ejemplo, unsigned char rgba [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 su lugar 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. ¿Trabaja en sistemas que tienen procesadores heterogéneos? ¿Tal vez usted tiene una CPU y una GPU? ¿Cómo saben qué endian está usando el otro? Es mucho mejor definir el orden de los bytes.

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.