【问题标题】:Resize (downsize) YUV420sp image调整(缩小)YUV420sp 图像的大小
【发布时间】:2013-06-19 09:04:33
【问题描述】:

我正在尝试调整(缩小)YUV420sp 格式的图像。是否可以在不将其转换为 RGB 的情况下进行此类图像调整大小,因此直接操作 YUV420sp 像素阵列?我在哪里可以找到这样的算法?

谢谢

【问题讨论】:

    标签: image-resizing yuv


    【解决方案1】:

    YUV 4:2:0 平面看起来像这样:

    ----------------------
    |     Y      | Cb|Cr |
    ----------------------
    

    地点:

    Y = width x height pixels
    Cb = Y / 4 pixels
    Cr = Y / 4 pixels
    
    Total num pixels (bytes) = width * height * 3 / 2
    

    而子采样是这样使用的:

    这意味着每个色度像素值在 4 个亮度像素之间共享。

    一种方法是去除像素,确保保持/重新计算相应的 Y-Cb-Cr 关系。

    Nearest-neighbor interpolation 接近但相反。

    另一种方法是先将 4:2:0 子采样转换为 4:4:4

    在这里,您可以在亮度和色度数据之间进行 1 对 1 的映射。

    这是在 4:2:0 和 4:2:2 之间插入色度的正确方法(亮度已经处于正确的分辨率) python中的代码,按照c-dito的html-link。 代码不是很pythonic,只是c版本的直接翻译。

    def __conv420to422(self, src, dst):
        """
        420 to 422 - vertical 1:2 interpolation filter
    
        Bit-exact with
        http://www.mpeg.org/MPEG/video/mssg-free-mpeg-software.html
        """
        w = self.width >> 1
        h = self.height >> 1
    
        for i in xrange(w):
            for j in xrange(h):
                j2 = j << 1
                jm3 = 0 if (j<3) else j-3
                jm2 = 0 if (j<2) else j-2
                jm1 = 0 if (j<1) else j-1
                jp1 = j+1 if (j<h-1) else h-1
                jp2 = j+2 if (j<h-2) else h-1
                jp3 = j+3 if (j<h-3) else h-1
    
                pel = (3*src[i+w*jm3]
                     -16*src[i+w*jm2]
                     +67*src[i+w*jm1]
                    +227*src[i+w*j]
                     -32*src[i+w*jp1]
                      +7*src[i+w*jp2]+128)>>8
    
                dst[i+w*j2] = pel if pel > 0 else 0
                dst[i+w*j2] = pel if pel < 255 else 255
    
                pel = (3*src[i+w*jp3]
                     -16*src[i+w*jp2]
                     +67*src[i+w*jp1]
                    +227*src[i+w*j]
                     -32*src[i+w*jm1]
                     +7*src[i+w*jm2]+128)>>8
    
                dst[i+w*(j2+1)] = pel if pel > 0 else 0
                dst[i+w*(j2+1)] = pel if pel < 255 else 255
        return dst
    

    运行两次以获得 4:4:4。 那么这只是删除行和列的问题。

    或者您可以将色度像素增加四倍以从 4:2:0 变为 4:4:4,删除行和列,然后将 4 个 Cb/Cr 值平均为 1 以恢复到 4:2:0同样,这完全取决于您需要有多严格:-)

    【讨论】:

    【解决方案2】:

    这是我用来将 YUV 420(或 NV21)缩小两倍的 Java 函数。

    该函数将字节数组中的图像与原始图像的宽度和高度一起作为输入,并返回一个字节数组中的图像,其宽度和高度都等于原始宽度和高度的一半。

    作为我的代码的基础,我使用了这个:Rotate an YUV byte array on Android

    public static byte[] halveYUV420(byte[] data, int imageWidth, int imageHeight) {
        byte[] yuv = new byte[imageWidth/2 * imageHeight/2 * 3 / 2];
        // halve yuma
        int i = 0;
        for (int y = 0; y < imageHeight; y+=2) {
            for (int x = 0; x < imageWidth; x+=2) {
                yuv[i] = data[y * imageWidth + x];
                i++;
            }
        }
        // halve U and V color components
        for (int y = 0; y < imageHeight / 2; y+=2) {
            for (int x = 0; x < imageWidth; x += 4) {
                yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x];
                i++;
                yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x + 1)];
                i++;
            }
        }
        return yuv;
    }
    

    【讨论】:

      【解决方案3】:

      YUV420sp 的 Y 在一个平面上,而 U&V 在另一个平面上。如果将 U&V 拆分为单独的平面,则可以依次对 3 个平面中的每一个执行相同的缩放操作,而无需先从 4:2:0 -> 4:4:4 开始。

      看看 libyuv 的源代码;它只是缩放飞机: https://code.google.com/p/libyuv/source/browse/trunk/source/scale.cc

      【讨论】:

        猜你喜欢
        • 2023-01-26
        • 1970-01-01
        • 2012-01-06
        • 2011-06-16
        • 2015-07-16
        • 2014-10-29
        • 1970-01-01
        • 1970-01-01
        • 2011-09-03
        相关资源
        最近更新 更多