Путаница в преобразовании YUV NV21 в RGB

Согласно http://developer.android.com/reference/android/graphics/ImageFormat.html#NV21 , NV21 используется по умолчанию.

В Интернете существует довольно много кода в отношении преобразования YUV NV21 в RGB. Однако, когда я просматриваю код, я сомневаюсь в правильности кода.

Сначала должен быть первый компонент V, за которым следует первый компонент U

Согласно http://wiki.videolan.org/YUV#NV21 , NV21 is like NV12, but with U and V order reversed: it starts with V. Однако, когда я прошел реализацию кода

  • Http://pastebin.com/T0my7zSc – Предполагается, что U на первом месте
  • Https://stackoverflow.com/a/8394202/72437 – Предполагается, что U тоже на первом месте
  • Https://stackoverflow.com/a/10125048/72437 – Это assmes U тоже на первом месте

R должна быть наиболее значимой позицией. Согласно внедрению int argb в Color.java , R должно быть в самом значительном положении. Однако я рассмотрел следующую реализацию кода

  • Http://pastebin.com/T0my7zSc – Предполагается, что R является наименее значимой позицией
  • Https://stackoverflow.com/a/8394202/72437 – Предполагается, что R является наименее значимым положением

Мне было интересно, они делают обычную ошибку, или я что-то упустил?

В настоящее время моя реализация такова.

 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; } } } 

Solutions Collecting From Web of "Путаница в преобразовании YUV NV21 в RGB"

Во-первых, я не супер опыт с кодировкой изображений (имеет ограниченное воздействие на это примерно год назад). Итак, возьмите мой ответ с солью.

Однако я считаю, что вы правы. Я думаю, что в их коде оба a) V и U перевернуты b) R и B перевернуты

У меня такое чувство, что, когда обе эти вещи перевернуты, он будет давать тот же результат, как если бы они не перевернулись. Именно по этой причине вы можете найти неправильный код во многих местах (изначально кто-то ошибся и после того, как он был скопирован по всем местам, потому что полученный код работает (однако, переменные называются неправильно)).

Вот еще один пример кода (который работает так же, как ваш): http://www.41post.com/3470/programming/android-retrieving-the-camera-preview-as-a-pixel-array

Такие термины, как «наиболее значимая позиция», неоднозначны, поскольку они зависят от конечного пользователя машины.

Когда все типы данных составляют 8 бит, существует простая однозначная спецификация: порядок байтов. Например, unsigned char rgba [4]; Будут иметь данные, хранящиеся как rgba [0] = r; Rgba [1] = g; Rgba [2] = b; Rgba [3] = a;

Или {r, g, b, a}, независимо от точности процессора.

Если вместо этого вы сделали

Int32 color = (r << 24) | (Г << 16) | (B << 8) | (A << 0);

Вы получите {r, g, b, a} в системе большого конца и {a, r, g, b} в системе little-endian. Вы работаете в системах с гетерогенными процессорами? Например, у вас есть процессор и графический процессор? Откуда они знают, какой эндиан использует другой? Вы намного лучше определяете порядок байтов.