将YUV4:4:4转换为YUV4:2:2图像

Naz*_*zar 1 image-processing yuv

互联网上有很多有关YUV4:4:4到YUV4:2:2格式之间差异的信息,但是,我找不到任何内容可以告诉您如何将YUV4:4:4转换为YUV4:2:2 。由于这种转换是使用软件执行的,因此我希望应该有一些开发人员完成该转换,并可以将我定向到描述转换算法的源代码中。当然,拥有软件代码会很不错,但是可以使用该理论就足以编写我自己的软件。具体来说,我想了解像素结构以及转换期间如何管理字节。

我发现像几个类似的问题这个这个,但是,不能让我回答过的问题。另外,我在摄影论坛上发布了这个问题,他们将其视为软件问题。

Rot*_*tem 7

之所以找不到特定的描述,是因为有很多方法可以做到。
让我们从维基百科开始:https ://en.wikipedia.org/wiki/Chroma_subsampling#4:2 :2

4:4:4:
三个Y'CbCr分量的采样率都相同,因此没有色度二次采样。该方案有时用于高端胶片扫描仪和电影后期制作中。

4:2:2:
以色度采样率的一半采样两个色度分量:水平色度分辨率减半。这将未压缩视频信号的带宽减少了三分之一,几乎没有视觉差异。

注意:术语YCbCr和YUV可互换使用。
https://zh.wikipedia.org/wiki/YCbCr

Y?CbCr通常与YUV色彩空间相混淆,并且通常YCbCr和YUV术语可以互换使用,从而引起一些混淆。当提到视频或数字形式的信号时,术语“ YUV”主要是指“ Y?CbCr”。

数据存储器排序:
同样,存在多种格式。
英特尔IPP文档定义了两个主要类别:“像素顺序图像格式”和“平面图像格式”。
这里有一个很好的文档:https : //software.intel.com/zh-cn/node/503876
请参阅此处:http : //www.fourcc.org/yuv.php#NV12了解YUV像素排列格式。
请参阅此处:http : //scc.ustc.edu.cn/zlsc/sugon/intel/ipp/ipp_manual/IPPI/ippi_ch6/ch6_image_downsampling.htm#ch6_image_downsampling以获取下采样说明。

让我们假设“像素顺序”格式:

YUV 4:4:4 data order: Y0 U0 V0  Y1 U1 V1  Y2 U2 V2  Y3 U3 V3  
YUV 4:2:2 data order: Y0  U0    Y1  V0    Y2  U1    Y3  V1  
Run Code Online (Sandbox Code Playgroud)

每个元素都是一个字节,Y0是内存中的低字节。
上述4:2:2数据顺序称为UYVY或YUY2像素格式。

转换算法:

  1. “朴素的子采样”:
    每秒钟U/ V组件“抛出” :
    Take U0,然后throw U1,take V0and throw V1...
    来源:Y0 U0 V0 Y1 U1 V1 Y2 U2 V2
    目的地:Y0 U0 Y1 V0 Y2 U2 Y3 V2
    我不推荐使用它,因为它会导致混淆现象

  2. 平均每U/ V对:
    采取目标U0等于源(U0+U1)/2,同为V0...
    来源:Y0 U0 V0 Y1 U1 V1 Y2 U2 V2
    目的地:Y0 (U0+U1)/2 Y1 (V0+V1)/2 Y2 (U2+U3)/2 Y3 (V2+V3)/2

  3. 使用其他插值方法对U和V进行下采样(例如三次插值)。
    通常,与简单平均值相比,您将看不到任何差异。


C实现:

该问题未标记为C,但是我认为以下C实现可能会有所帮助。
以下代码通过平均每个U / V对将按像素排序的YUV 4:4:4转换为按像素排序的YUV 4:2:2:

YUV 4:4:4 data order: Y0 U0 V0  Y1 U1 V1  Y2 U2 V2  Y3 U3 V3  
YUV 4:2:2 data order: Y0  U0    Y1  V0    Y2  U1    Y3  V1  
Run Code Online (Sandbox Code Playgroud)

YUV 4:2:2的平面表示

平面表示可能比“像素顺序”格式更直观。
在平面表示中,每个颜色通道均表示为单独的矩阵,可以将其显示为图像。

例:

  • RGB格式的原始图像(转换为YUV之前):
    RGB格式的原始图像

  • YUV 4:4:4格式的图像通道:
    图片格式为YUV 4:4:4
    (左YUV三元组以灰度级表示,右YUV三元组用假色表示)。

  • YUV 4:2:2格式的图像通道(水平色度二次采样后):
    图片格式为YUV 4:2:2
    (左YUV三元组用灰度表示,右YUV三元组用“假色”表示)。

如您所见,在4:2:2格式中,U和V通道在水平轴上被下采样(缩小)。

备注:
U和V通道的“假色”表示用于强调Y是亮度通道,而U和V是色度通道。


高阶插值和抗锯齿滤波器:
以下MATLAB代码示例演示了如何使用高阶插值和抗锯齿滤波器执行下采样。
该样本还显示了FFMPEG使用的下采样方法。
注意:您无需了解MATLAB编程即可了解示例。
您确实需要通过内核和图像之间的卷积来掌握一些图像过滤的知识。

//Convert single row I0 from pixel-ordered YUV 4:4:4 to pixel-ordered YUV 4:2:2.
//Save the result in J0.
//I0 size in bytes is image_width*3
//J0 size in bytes is image_width*2
static void ConvertRowYUV444ToYUV422(const unsigned char I0[],
                                     const int image_width,
                                     unsigned char J0[])
{
    int x;

    //Process two Y,U,V triples per iteration:
    for (x = 0; x < image_width; x += 2)
    {
        //Load source elements
        unsigned char y0    = I0[x*3];                  //Load source Y element
        unsigned int u0     = (unsigned int)I0[x*3+1];  //Load source U element (and convert from uint8 to uint32).
        unsigned int v0     = (unsigned int)I0[x*3+2];  //Load source V element (and convert from uint8 to uint32).

        //Load next source elements
        unsigned char y1    = I0[x*3+3];                //Load source Y element
        unsigned int u1     = (unsigned int)I0[x*3+4];  //Load source U element (and convert from uint8 to uint32).
        unsigned int v1     = (unsigned int)I0[x*3+5];  //Load source V element (and convert from uint8 to uint32).

        //Calculate destination U, and V elements.
        //Use shift right by 1 for dividing by 2.
        //Use plus 1 before shifting - round operation instead of floor operation.
        unsigned int u01    = (u0 + u1 + 1) >> 1;       //Destination U element equals average of two source U elements.
        unsigned int v01    = (v0 + v1 + 1) >> 1;       //Destination U element equals average of two source U elements.

        J0[x*2]     = y0;   //Store Y element (unmodified).
        J0[x*2+1]   = (unsigned char)u01;   //Store destination U element (and cast uint32 to uint8).
        J0[x*2+2]   = y1;   //Store Y element (unmodified).
        J0[x*2+3]   = (unsigned char)v01;   //Store destination V element (and cast uint32 to uint8).
    }
}


//Convert image I from pixel-ordered YUV 4:4:4 to pixel-ordered YUV 4:2:2.
//I - Input image in pixel-order data YUV 4:4:4 format.
//image_width - Number of columns of image I.
//image_height - Number of rows of image I.
//J - Destination "image" in pixel-order data YUV 4:2:2 format.
//Note: The term "YUV" referees to "Y'CbCr".

//I is pixel ordered YUV 4:4:4 format (size in bytes is image_width*image_height*3):
//YUVYUVYUVYUV
//YUVYUVYUVYUV
//YUVYUVYUVYUV
//YUVYUVYUVYUV
//
//J is pixel ordered YUV 4:2:2 format (size in bytes is image_width*image_height*2):
//YUYVYUYV
//YUYVYUYV
//YUYVYUYV
//YUYVYUYV
//
//Conversion algorithm:
//Each element of destination U is average of 2 original U horizontal elements
//Each element of destination V is average of 2 original V horizontal elements
//
//Limitations:
//1. image_width must be a multiple of 2.
//2. I and J must be two separate arrays (in place computation is not supported). 
static void ConvertYUV444ToYUV422(const unsigned char I[],
                                  const int image_width,
                                  const int image_height,
                                  unsigned char J[])
{
    //I0 points source row.
    const unsigned char *I0;    //I0 -> YUYVYUYV...

    //J0 and points destination row.
    unsigned char *J0;          //J0 -> YUYVYUYV

    int y;  //Row index

    //In each iteration process single row.
    for (y = 0; y < image_height; y++)
    {
        I0 = &I[y*image_width*3];   //Input row width is image_width*3 bytes (each pixel is Y,U,V).

        J0 = &J[y*image_width*2];   //Output row width is image_width*2 bytes (each two pixels are Y,U,Y,V).

        //Process single source row into single destination row
        ConvertRowYUV444ToYUV422(I0, image_width, J0);
    }
}
Run Code Online (Sandbox Code Playgroud)

不同种类的下采样方法的示例。
使用抗锯齿滤波器的线性插值与三次插值:
在第一个示例(山man)中,没有可见的差异。
在第二个示例(圆形和矩形)中,可见的差异很小。
第三个示例(行)演示了混叠工件。
备注:显示的图像是使用三次插值从YUV422向上采样到YUV444并从YUV444转换为RGB的图像。

  • 线性插值与三次抗锯齿(山d):
    线性插值与三次抗锯齿(mandrill)

  • 线性插值与三次抗锯齿(圆形和矩形):
    线性插值与三次抗锯齿(圆形和矩形)

  • 线性插值与三次使用抗锯齿(演示锯齿伪像):
    展示别名工件

  • 真是个好答案!所有网站都重复/重新措辞相同的内容,但没有重点。感谢您收集信息并使其清晰。像素顺序图像格式表(来自您的链接之一)几乎可以回答我的问题-它声明了重新采样的YUV序列-尽管在[这里](https:/ /www.cs.cf.ac.uk/Dave/Multimedia/node196.html)。我会尽力让您知道。为了正确起见,在平均目标位置时,您是指_Y3(V2 + V3)/ 2_吗? (2认同)