簡體   English   中英

如何使用IPP將8位灰度圖像轉換為NV12(限制范圍)色彩空間

[英]How to convert 8 bits Grayscale image to NV12 (limited range) color space using IPP

像Intel®MediaSDK這樣的視頻編碼器不接受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 = round(I * 0.859 + 16)。

使用IPP進行上述轉換的有效方法是什么?

我正在為自己的問題添加一個答案。
我希望看到更好的答案......

我找到了一個使用兩個IPP功能的解決方案:

我選擇了使用定點數學運算的函數,以獲得更好的性能。

  • 通過擴展,縮放和移位來執行0.859縮放的定點實現。 示例: b = (a*scale + (1<<7)) >> 8; [當scale = (0.859)*2^8 ]。
    ippsMulC_8u_Sfs val參數設置為round(0.859*2^8) = 220
    ippsMulC_8u_Sfs scaleFactor參數設置為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]來代替[ 16235 ],和UV范圍也[0,255])。
使用“全范圍”標准允許放置I代替Y (即Y = I )。

使用英特爾媒體SDK將流標記為“全范圍”是可能的(但沒有詳細記錄)。
將H.264流標記為“全范圍”需要添加指向mfxExtBuffer **ExtParam指針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是設置“全范圍”視頻的唯一相關參數,但我們必須填充整個結構。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM