Преобразование yuv420p в rgb888 в C

Я пытаюсь преобразовать планарный YUV (yuv420p) в RGB24 в C.

Я не контролирую ввод и имею данные YUV в виде 3 отдельных буферов, один для Y, один для U и один для V .

Я хочу создать один выходной буфер RGB из этих трех входных буферов.

Я следовал следующей схеме на вики, но у меня есть проблема с моим кодом, так как выходное изображение имеет неправильные цвета.

Вот моя функция (извините за грубость…)

static uint8_t* yuv420p_to_rgb2(const uint8_t* y, const uint8_t* u, const uint8_t* v, const size_t width, const size_t height)
{
    const size_t size = width * height;
    uint8_t* rgb = (uint8_t*)calloc((size * 3), sizeof(uint8_t));

    int uv_index = 0, pass = 0;
    int b,g,r;
    uint8_t* ptr = rgb;
    for (size_t i = 0; i < size; i += 6)
    {
        if (pass == 2)
        {
            pass = 0;
            uv_index += 3;
        }
        int y1 = y[i];
        int y2 = y[i+1];
        int y3 = y[i+2];
        int y4 = y[i+3];
        int y5 = y[i+4];
        int y6 = y[i+5];

        int u1 = u[uv_index];
        int u2 = u[uv_index+1];
        int u3 = u[uv_index+2];

        int v1 = v[uv_index];
        int v2 = v[uv_index+1];
        int v3 = v[uv_index+2];
        //1
        r = 1.164 * (y1 - 16) + 1.596 * (v1 - 128);
        g = 1.164 * (y1 - 16) - 0.813 * (v1 - 128) - 0.391 * (u1 - 128);
        b = 1.164 * (y1 - 16) + 2.018 * (u1 - 128);
        *ptr++ = CLAMP(r);
        *ptr++ = CLAMP(g);
        *ptr++ = CLAMP(b);
        //2
        r = 1.164 * (y2 - 16) + 1.596 * (v1 - 128);
        g = 1.164 * (y2 - 16) - 0.813 * (v1 - 128) - 0.391 * (u1 - 128);
        b = 1.164 * (y2 - 16) + 2.018 * (u1 - 128);
        *ptr++ = CLAMP(r);
        *ptr++ = CLAMP(g);
        *ptr++ = CLAMP(b);
        //3
        r = 1.164 * (y3 - 16) + 1.596 * (v2 - 128);
        g = 1.164 * (y3 - 16) - 0.813 * (v2 - 128) - 0.391 * (u2 - 128);
        b = 1.164 * (y3 - 16) + 2.018 * (u2 - 128);
        *ptr++ = CLAMP(r);
        *ptr++ = CLAMP(g);
        *ptr++ = CLAMP(b);
        //4
        r = 1.164 * (y4 - 16) + 1.596 * (v2 - 128);
        g = 1.164 * (y4 - 16) - 0.813 * (v2 - 128) - 0.391 * (u2 - 128);
        b = 1.164 * (y4 - 16) + 2.018 * (u2 - 128);
        *ptr++ = CLAMP(r);
        *ptr++ = CLAMP(g);
        *ptr++ = CLAMP(b);
        //5
        r = 1.164 * (y5 - 16) + 1.596 * (v3 - 128);
        g = 1.164 * (y5 - 16) - 0.813 * (v3 - 128) - 0.391 * (u3 - 128);
        b = 1.164 * (y5 - 16) + 2.018 * (u3 - 128);
        *ptr++ = CLAMP(r);
        *ptr++ = CLAMP(g);
        *ptr++ = CLAMP(b);
        //6
        r = 1.164 * (y6 - 16) + 1.596 * (v3 - 128);
        g = 1.164 * (y6 - 16) - 0.813 * (v3 - 128) - 0.391 * (u3 - 128);
        b = 1.164 * (y6 - 16) + 2.018 * (u3 - 128);
        *ptr++ = CLAMP(r);
        *ptr++ = CLAMP(g);
        *ptr++ = CLAMP(b);

        pass++;
    }

    return rgb;
}

Результат (верхнее изображение — мой результат, нижнее — то, что должно быть): введите здесь описание изображения

Спасибо за вашу помощь.


person Sawa-chan    schedule 19.02.2015    source источник
comment
Попробуйте добавить альфа-слой, это может помочь (но это довольно долго объяснять и не очень хорошо укладывается в моей голове, поэтому я не могу прямо сейчас)   -  person Thomas Ayoub    schedule 19.02.2015
comment
Добавление альфа-канала тривиально, но я не вижу смысла, это ничего не изменит…   -  person Nyx0uf    schedule 19.02.2015


Ответы (1)


Вы неправильно получаете значения U и V.

Значения U и V для пикселя (i, j):

u[((j / 2) * (width / 2)) + (i / 2)];
v[((j / 2) * (width / 2)) + (i / 2)];

Итак, попробуйте такой цикл:

for (int j = 0; j < height; j++) {
    for (int i = 0; i < width; i++) {
        int yy = y[(j * width) + i];
        int uu = u[((j / 2) * (width / 2)) + (i / 2)];
        int vv = v[((j / 2) * (width / 2)) + (i / 2)];

        r = 1.164 * (yy - 16) + 1.596 * (vv - 128);
        g = 1.164 * (yy - 16) - 0.813 * (vv - 128) - 0.391 * (uu - 128);
        b = 1.164 * (yy - 16) + 2.018 * (uu - 128);
        *ptr++ = CLAMP(r);
        *ptr++ = CLAMP(g);
        *ptr++ = CLAMP(b);
    }
}
person Sander De Dycker    schedule 19.02.2015
comment
Это псевдоязык? - person Rilakkuma; 15.02.2016
comment
@Rilakkuma: как и в вопросе, этот код написан на C. - person Sander De Dycker; 15.02.2016
comment
Для тех, кто ищет CLAMP(), это прекрасно работает: uint8_t clamp(int16_t value) { return value<0 ? 0 : (value>255 ? 255 : value); } - person Shane Smiskol; 23.02.2020