[英]How to convert 8 bits Grayscale image to NV12 (limited range) color space using IPP
Video encoders like Intel® Media SDK do not accept 8 bits Grayscale image as input format. 像Intel®MediaSDK这样的视频编码器不接受8位灰度图像作为输入格式。
8 bits Grayscale format applies one byte per pixel in range [0, 255]. 8位灰度格式在范围[0,255]中每像素应用一个字节。
8 bits YUV format in the context of the question applies YCbCr (BT.601 or BT.709). 在问题的上下文中的8比特YUV格式应用YCbCr (BT.601或BT.709)。
Although there is a full range YUV standard, the commonly used format is "limited range" YUV, where range of Y is [16, 235] and range of U,V is [16, 240]. 虽然有全范围的YUV标准,但常用的格式是“有限范围”YUV,其中Y的范围是[16,235],U,V的范围是[16,240]。
NV12 format is the common input format in this case. 在这种情况下, NV12格式是常见的输入格式。
NV12 format is YUV 4:2:0 format ordered in memory with a Y plane first, followed by packed chroma samples in interleaved UV plane: NV12格式是YUV 4:2:0格式,在内存中首先排列Y平面,然后是交错UV平面中的打包色度样本:
YYYYYY
YYYYYY
UVUVUV
The Grayscale image will be referred as "I plane": 灰度图像将被称为“I平面”:
IIIIII
IIIIII
Setting the UV plane is simple: Set all U,V elements to 128 value. 设置UV平面很简单:将所有U,V元素设置为128值。
But what about the Y plane? 但Y飞机怎么样?
In case of full range YUV, we can simply put "I plane" as Y plane (ie Y = I). 在全范围YUV的情况下,我们可以简单地将“I平面”作为Y平面(即Y = I)。
In case of "limited" YUV format, a transformation is required: 在“有限”YUV格式的情况下,需要进行转换:
Setting R=G=B in the conversion formula results: Y = round(I*0.859 + 16). 在转换公式中设置R = G = B结果: Y = round(I * 0.859 + 16)。
What is the efficient way to do the above conversion using IPP ? 使用IPP进行上述转换的有效方法是什么?
I am adding an answer to my own question. 我正在为自己的问题添加一个答案。
I hope to see a better answer... 我希望看到更好的答案......
I found a solution using two IPP functions: 我找到了一个使用两个IPP功能的解决方案:
I selected functions that uses fixed point math, for better performance. 我选择了使用定点数学运算的函数,以获得更好的性能。
0.859
scaling is performed by expanding, scaling and shifting. 0.859
缩放的定点实现。 Example: b = (a*scale + (1<<7)) >> 8;
b = (a*scale + (1<<7)) >> 8;
[When scale
= (0.859)*2^8
]. scale
= (0.859)*2^8
]。 val
parameter to ippsMulC_8u_Sfs
set to round(0.859*2^8)
= 220
. ippsMulC_8u_Sfs
val
参数设置为round(0.859*2^8)
= 220
。 scaleFactor
parameter to ippsMulC_8u_Sfs
set to 8
(divide the scaled result by 2^8
). ippsMulC_8u_Sfs
scaleFactor
参数设置为8
(将缩放结果除以2^8
)。 Code sample: 代码示例:
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);
}
Out of topic note: 超出主题说明:
There is a way to mark a video stream as "full range" (where Y
range is [0, 255] instead of [ 16
, 235
], and U
, V
range is also [0, 255]). 有一种方法来标记的视频流为“全范围”(其中
Y
范围是[0,255]来代替[ 16
, 235
],和U
, V
范围也[0,255])。
Using the "full range" standard allows placing I
in place of Y
(ie Y = I ). 使用“全范围”标准允许放置
I
代替Y
(即Y = I )。
Marking the stream as "full range" using Intel Media SDK, is possible (but not well documented). 使用英特尔媒体SDK将流标记为“全范围”是可能的(但没有详细记录)。
Marking H.264 stream as "full range" requires to add pointer to mfxExtBuffer **ExtParam
list (in structure mfxVideoParam
): 将H.264流标记为“全范围”需要添加指向
mfxExtBuffer **ExtParam
指针mfxExtBuffer **ExtParam
列表(在结构mfxVideoParam
):
A pointer to structure of type mfxExtVideoSignalInfo
should be added with the following values: 应使用以下值添加指向
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
is the only relevant parameter of setting "full range" video, but we must fill the entire structure. VideoFullRange = 1
是设置“全范围”视频的唯一相关参数,但我们必须填充整个结构。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.