调整大小(缩小尺寸)YUV420sp图像

时间:2013-06-19 09:04:34

标签: image-resizing yuv

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

谢谢

3 个答案:

答案 0 :(得分:16)

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

以下使用的子网:

420

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

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

接近Nearest-neighbor interpolation但反转的东西。

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

444

这里有亮度和色度数据之间的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再一次,这一切都取决于你需要多严格: - )

答案 1 :(得分:7)

这是一个Java函数,用于将YUV 420(或NV21)缩小两倍。

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

作为我的代码的基础,我使用了这个: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;
}

答案 2 :(得分:1)

YUV420sp在一个平面中具有Y而在另一个平面中具有U&amp; V.如果你拆分U&amp; V进入单独的平面,然后您可以依次对3个平面中的每个平面执行相同的缩放操作,而无需首先从4:2:0 - > 4:4:4

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