Как преобразовать 8-битное изображение в градациях серого в цветовое пространство NV12 (ограниченный диапазон) с помощью IPP

Видеокодировщики, такие как Intel® Media SDK, не принимают 8-битное изображение в оттенках серого в качестве входного формата.
8-битное оттенки серого применяется один байт на пиксель в диапазоне [0, 255].

8-битный формат YUV в контексте вопроса применяется YCbCr (BT.601 или BT.709). ).
Несмотря на то, что существует полный стандарт YUV, обычно используется формат YUV с «ограниченным диапазоном», где диапазон Y равен [16, 235], а диапазон U, V равен [16, 240].

формат NV12 – это общий формат ввода в данном случае.
Формат NV12 – YUV. Формат 4:2:0 упорядочен в памяти с плоскостью Y, за которой следуют упакованные образцы цветности в чередующейся плоскости UV:
YYYYYY
YYYYYY
UVUVUV

введите здесь описание изображения

Изображение в градациях серого будет обозначаться как "I-плоскость":
IIIIII
IIIIII

введите здесь описание изображения

Установить UV-плоскость очень просто: установите для всех элементов U, V значение 128.

А как же самолет Y?

В случае полного диапазона YUV мы можем просто поставить «плоскость I» как плоскость Y (т. е. Y = I).

В случае "ограниченного" формата YUV требуется преобразование:
Установка R=G=B в формуле преобразования приводит к следующему результату: Y = округление (I*0,859 + 16).

Каков эффективный способ выполнить описанное выше преобразование с помощью IPP?


person Rotem    schedule 22.06.2016    source источник
comment
Я бы использовал полный диапазон Y от 0 до 255 без преобразования, поскольку для этой практики существует сильный прецедент, даже если он противоречит исходному определению яркости.   -  person R.. GitHub STOP HELPING ICE    schedule 23.06.2016
comment
Вы уверены, что Media SDK не поддерживает grey8? А как насчет MFX_CHROMAFORMAT_MONOCHROME ?   -  person apalopohapa    schedule 11.02.2017
comment
@apalopohapa Нет, я не уверен ... Насколько я помню, когда я использовал видеокодер H.264, единственным поддерживаемым форматом (без использования преобразования цветового пространства VPP) был NV12.   -  person Rotem    schedule 11.02.2017


Ответы (1)


Я добавляю ответ на свой вопрос.
Надеюсь увидеть лучший ответ...

Я нашел решение, используя две функции IPP:

  • ippsMulC_8u_Sfs — умножает каждый элемент вектора на постоянное значение.
  • ippsAddC_8u_ISfs — добавляет постоянное значение к каждому элементу вектора.

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

  • Реализация фиксированной точки 0.859 масштабирования выполняется путем расширения, масштабирования и смещения. Пример: b = (a*scale + (1<<7)) >> 8; [Когда scale = (0.859)*2^8].
    Параметр val для ippsMulC_8u_Sfs устанавливается равным round(0.859*2^8) = 220.
    Параметр scaleFactor для ippsMulC_8u_Sfs устанавливается равным 8 (разделите масштабированный результат на 2^8).

Пример кода:

void GrayscaleToNV12(const unsigned char I[],
                     int image_width,
                     int image_height,
                     unsigned char J[])
{
    IppStatus ipp_status;
    const int image_size = image_width*image_height;

    unsigned char *UV = &J[image_size]; //In NV12 format, UV plane starts below Y.

    const Ipp8u expanded_scaling = (Ipp8u)(0.859 * 256.0 + 0.5);

    //J[x] = (expanded_scaling * I[x] + 128u) >> 8u;
    ipp_status = ippsMulC_8u_Sfs(I,                 //const Ipp8u* pSrc,
                                 expanded_scaling,  //Ipp8u val,
                                 J,                 //Ipp8u* pDst,
                                 image_size,        //int len,
                                 8);                //int scaleFactor);

    //Check ipp_status, and handle errors...

    //J[x] += 16;
    //ippsAddC_8u_ISfs is deprecated, I used it to keep the code simple.
    ipp_status = ippsAddC_8u_ISfs(16,           //Ipp8u val, 
                                  J,            //Ipp8u* pSrcDst, 
                                  image_size,   //int len, 
                                  0);           //int scaleFactor);

    //Check ipp_status, and handle errors...

    //2. Fill all UV plane with 128 value - "gray color".
    memset(UV, 128, image_width*image_height/2);
}

Примечание не по теме.
Существует способ пометить видеопоток как "полный диапазон" (где Y диапазон равен [0, 255] вместо [16, 235] и U, Диапазон V также равен [0, 255]).
Использование стандарта "полный диапазон" позволяет разместить I вместо Y (т. е. Y = I).

Пометка потока как «полного диапазона» с помощью Intel Media SDK возможна (но недостаточно документирована).
Чтобы пометить поток H.264 как «полный диапазон», необходимо добавить указатель на список mfxExtBuffer **ExtParam (в структуре mfxVideoParam):
Указатель на структуру типа mfxExtVideoSignalInfo нужно добавить со следующими значениями:

typedef struct {
    mfxExtBuffer Header; //MFX_EXTBUFF_VIDEO_SIGNAL_INFO and sizeof(mfxExtVideoSignalInfo)
    mfxU16 VideoFormat; //Most likely 5 ("Unspecified video format")
    mfxU16 VideoFullRange; //1 (video_full_range_flag is equal to 1)
    mfxU16 ColourDescriptionPresent; //0 (description_present_flag equal to 0)
    mfxU16 ColourPrimaries; //0 (no affect when ColourDescriptionPresent = 0)
    mfxU16 TransferCharacteristics; //0 (no affect when ColourDescriptionPresent = 0)
    mfxU16 MatrixCoefficients; //0 (no affect when ColourDescriptionPresent = 0)
} mfxExtVideoSignalInfo; 

VideoFullRange = 1 — единственный важный параметр настройки «полного диапазона» видео, но мы должны заполнить всю структуру.

person Rotem    schedule 26.06.2016