Преобразование цвета из RGB в YUV (YCoCg)

Я пытаюсь реализовать преобразование цвета Func, которое выводит в 3 отдельных буфера. Функция rgb_to_ycocg имеет 4x8-битный канальный буфер с чередованием (BGRA) и 3 выходных буфера (Y, Co и Cg), каждый из которых имеет 16-битные значения. В настоящее время я использую этот фрагмент кода:

void rgb_to_ycocg(const uint8_t *pSrc, int32_t srcStep, int16_t *pDst[3], int32_t dstStep[3], int width, int height)
{
    Buffer<uint8_t> inRgb((uint8_t *)pSrc, 4, width, height);
    Buffer<int16_t> outY(pDst[0], width, height);
    Buffer<int16_t> outCo(pDst[1], width, height);
    Buffer<int16_t> outCg(pDst[2], width, height);

    Var x, y, c;
    Func calcY, calcCo, calcCg, inRgb16;

    inRgb16(c, x, y) = cast<int16_t>(inRgb(c, x, y));

    calcY(x, y) = (inRgb16(0, x, y) + ((inRgb16(2, x, y) - inRgb16(0, x, y)) >> 1)) + ((inRgb16(1, x, y) - (inRgb16(0, x, y) + ((inRgb16(2, x, y) - inRgb16(0, x, y)) >> 1))) >> 1);
    calcCo(x, y) = inRgb16(2, x, y) - inRgb16(0, x, y);
    calcCg(x, y) =  inRgb16(1, x, y) - (inRgb16(0, x, y) + ((inRgb16(2, x, y) - inRgb16(0, x, y)) >> 1));

    Pipeline p =Pipeline({calcY, calcCo, calcCg});
    p.vectorize(x, 16).parallel(y);
    p.realize({ outY, outCo, outCg });
}

Проблема в том, что я получаю низкую производительность по сравнению с эталонной реализацией (базовые циклы for в c). Я понимаю, что мне нужно попробовать лучшее планирование, но я думаю, что делаю что-то неправильно с точки зрения буферов ввода/вывода. Я видел учебники и пытался придумать способ вывода в несколько буферов. Использование Pipeline было единственным способом, который я смог найти. Не лучше ли мне сделать 3 Func и вызывать их по отдельности? Это правильное использование класса Pipeline?


person Philippe Paré    schedule 16.03.2017    source источник


Ответы (1)


Большая возможная проблема заключается в том, что вы создаете и компилируете код каждый раз, когда хотите преобразовать одно изображение. Это было бы действительно очень медленно. Используйте ImageParams вместо буферов, определите конвейер один раз, а затем реализуйте его несколько раз.

Эффект второго порядка заключается в том, что я думаю, что вам действительно нужен кортеж, а не конвейер. Tuple Func вычисляет все свои значения в одном и том же внутреннем цикле, который будет повторно использовать загрузки из inRgb и т. д. На данный момент игнорируя проблему перекомпиляции, попробуйте:

void rgb_to_ycocg(const uint8_t *pSrc, int32_t srcStep, int16_t *pDst[3], int32_t dstStep[3], int width, int height)
{
    Buffer<uint8_t> inRgb((uint8_t *)pSrc, 4, width, height);
    Buffer<int16_t> outY(pDst[0], width, height);
    Buffer<int16_t> outCo(pDst[1], width, height);
    Buffer<int16_t> outCg(pDst[2], width, height);

    Var x, y, c;
    Func calcY, calcCo, calcCg, inRgb16;

    inRgb16(c, x, y) = cast<int16_t>(inRgb(c, x, y));

    out(x, y) = {
        inRgb16(0, x, y) + ((inRgb16(2, x, y) - inRgb16(0, x, y)) >> 1)) + ((inRgb16(1, x, y) - (inRgb16(0, x, y) + ((inRgb16(2, x, y) - inRgb16(0, x, y)) >> 1))) >> 1),
        inRgb16(2, x, y) - inRgb16(0, x, y),
        inRgb16(1, x, y) - (inRgb16(0, x, y) + ((inRgb16(2, x, y) - inRgb16(0, x, y)) >> 1))
    };

    out.vectorize(x, 16).parallel(y);
    out.realize({ outY, outCo, outCg });
}
person Andrew Adams    schedule 16.03.2017
comment
спасибо за ответ, я знаю о проблеме перекомпиляции, но я рад видеть, что это можно сделать с помощью кортежей. Я попробую это завтра. еще раз спасибо! - person Philippe Paré; 16.03.2017