Подтвердить что ты не робот

Путаница в преобразовании 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. Однако, когда я прошел реализацию кода

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

  • http://pastebin.com/T0my7zSc - Предполагается, что R находится в наименее значимой позиции
  • qaru.site/info/55158/... - Предполагается, что 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;
        }
    }
}
4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

Когда все типы данных составляют 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) | (g < 16) | (b < 8) | (a < 0);

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