代码之家  ›  专栏  ›  技术社区  ›  Brian Hamill

Numpy调整图像大小/重缩放图像

  •  167
  • Brian Hamill  · 技术社区  · 7 年前

    我想拍摄一张图像并更改图像的比例,而它是一个numpy数组。

    例如,我有一个可口可乐瓶的图像: bottle-1

    转化为形状的numpy数组 (528, 203, 3) 我想调整它的大小,即第二幅图像的大小: bottle-2

    形状为 (140, 54, 3) .

    如何将图像的大小更改为特定形状,同时仍保持原始图像?其他答案建议每隔一行或第三行剥离一行,但我想做的基本上是通过图像编辑器缩小图像,但使用python代码。在numpy/SciPy中有任何库可以这样做吗?

    10 回复  |  直到 7 年前
        1
  •  192
  •   willeM_ Van Onsem    6 年前

    是的,你可以安装 opencv (这是一个用于图像处理和计算机视觉的库),并使用 cv2.resize 作用例如,使用:

    import cv2
    import numpy as np
    
    img = cv2.imread('your_image.jpg')
    res = cv2.resize(img, dsize=(54, 140), interpolation=cv2.INTER_CUBIC)

    在这里 img 因此是一个包含原始图像的numpy数组,而 res 是包含 已调整大小 形象一个重要方面是 interpolation 参数:有几种方法可以调整图像大小。尤其是当您缩小图像时,原始图像的大小是 已调整大小的图像大小的倍数。可能的插值模式包括:

    • INTER_NEAREST -最近邻插值
    • INTER_LINEAR -双线性插值(默认情况下使用)
    • INTER_AREA -使用像素面积关系重新采样。这可能是图像抽取的首选方法,因为它可以消除莫尔 后果但当图像缩放时,它与 INTER\u最近 方法
    • INTER_CUBIC -4x4像素邻域上的双三次插值
    • INTER_LANCZOS4 -8x8像素邻域上的Lanczos插值

    与大多数选项一样,没有“最佳”选项,因为对于每个调整大小模式,都存在一种策略优于另一种策略的情况。

        2
  •  111
  •   jakevdp    5 年前

    虽然可以单独使用numpy来执行此操作,但此操作不是内置的。也就是说,你可以使用 scikit-image (建立在numpy上)来进行这种图像处理。

    Scikit图像重缩放文档是 here .

    例如,可以对图像执行以下操作:

    from skimage.transform import resize
    bottle_resized = resize(bottle, (140, 54))
    

    这将为您解决插值、抗锯齿等问题。

        3
  •  29
  •   Waylon Flinn    5 年前

    对于那些从谷歌来这里寻找快速减少图像采样方法的人来说 numpy 用于机器学习应用程序的数组,这里有一个超快速方法(改编自 here ). 仅当输入维度是输出维度的倍数时,此方法才有效。

    以下示例将样本从128x128减少到64x64(这很容易更改)。

    频道上次订购

    # large image is shape (128, 128, 3)
    # small image is shape (64, 64, 3)
    input_size = 128
    output_size = 64
    bin_size = input_size // output_size
    small_image = large_image.reshape((output_size, bin_size, 
                                       output_size, bin_size, 3)).max(3).max(1)
    

    频道首次订购

    # large image is shape (3, 128, 128)
    # small image is shape (3, 64, 64)
    input_size = 128
    output_size = 64
    bin_size = input_size // output_size
    small_image = large_image.reshape((3, output_size, bin_size, 
                                          output_size, bin_size)).max(4).max(2)
    

    对于灰度图像,只需更改 3 到a 1 这样地:

    频道首次订购

    # large image is shape (1, 128, 128)
    # small image is shape (1, 64, 64)
    input_size = 128
    output_size = 64
    bin_size = input_size // output_size
    small_image = large_image.reshape((1, output_size, bin_size,
                                          output_size, bin_size)).max(4).max(2)
    

    此方法使用等效的最大池。这是我找到的最快的方法。

        4
  •  20
  •   matwilso    3 年前

    单线numpy解决方案 降采样 (2人):

    smaller_img = bigger_img[::2, ::2]
    

    上采样 (2人):

    bigger_img = smaller_img.repeat(2, axis=0).repeat(2, axis=1)
    

    (这将HxWxC形状的图像。在上述注释中,h/t为L.K·rkk·inen。请注意,此方法仅允许调整整个整数的大小(例如,2x,但不允许1.5x))

        5
  •  18
  •   Community George Mulligan    4 年前

    如果有人来这里寻找一种在Python中缩放/调整图像大小的简单方法,而不需要使用其他库,那么这里有一个非常简单的图像大小调整函数:

    #simple image scaling to (nR x nC) size
    def scale(im, nR, nC):
      nR0 = len(im)     # source number of rows 
      nC0 = len(im[0])  # source number of columns 
      return [[ im[int(nR0 * r / nR)][int(nC0 * c / nC)]  
                 for c in range(nC)] for r in range(nR)]
    

    用法示例:将(30 x 30)图像大小调整为(100 x 200):

    import matplotlib.pyplot as plt
    
    def sqr(x):
      return x*x
    
    def f(r, c, nR, nC):
      return 1.0 if sqr(c - nC/2) + sqr(r - nR/2) < sqr(nC/4) else 0.0
    
    # a red circle on a canvas of size (nR x nC)
    def circ(nR, nC):
      return [[ [f(r, c, nR, nC), 0, 0] 
                 for c in range(nC)] for r in range(nR)]
    
    plt.imshow(scale(circ(30, 30), 100, 200))
    

    输出: scaled image

    这可以缩小/缩放图像,并且可以很好地处理numpy阵列。

        6
  •  4
  •   Cold Eye    3 年前

    对于想要调整(插入)一批numpy数组大小的人,pytorch提供了更快的函数名 torch.nn.functional.interpolate ,请记住使用np。首先转置,将通道从batchxWxHx3更改为batchx3xWxH。

        7
  •  3
  •   cemsazara    6 年前

    SciPy的 imresize() 方法是另一种调整大小的方法,但它将从SciPy v 1.3.0开始删除。SciPy指 PIL公司 图像大小调整方法: Image.resize(size, resample=0)

    大小 –以像素为单位的请求大小,作为2元组:(宽度、高度)。
    重新采样 –可选的重采样过滤器。这可能是PIL之一。形象最近的(使用最近的邻居),PIL。形象双线性(线性插值),PIL。形象双三次(三次样条插值)或PIL。形象LANCZOS(高质量下采样滤波器)。如果省略,或者如果图像具有模式-1-P-P,则设置为PIL。形象最近的。

    此处链接: https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.Image.resize

        8
  •  2
  •   Joseph Catrambone    3 年前

    几年后偶然发现了这一点。到目前为止,答案似乎可以分为以下几类:

    1. 使用外部库。(OpenCV、SciPy等)
    2. 二次缩放的用户功率
    3. 使用最近邻居

    这些解决方案都是值得尊敬的,所以我提供这些只是为了完整性。 它有三个优点:(1)它可以接受任意分辨率,甚至是两个标度因子的非幂次;(2) 它使用纯Python+Numpy,没有外部库;(3)它会对所有像素进行插值,以获得“更好看”的结果。

    它没有很好地利用Numpy,因此 不快 ,尤其是对于大型图像。如果您只是重新缩放较小的图像,应该可以。我根据Apache或MIT许可证提供此服务,由用户自行决定。

    import math
    import numpy
    
    def resize_linear(image_matrix, new_height:int, new_width:int):
        """Perform a pure-numpy linear-resampled resize of an image."""
        output_image = numpy.zeros((new_height, new_width), dtype=image_matrix.dtype)
        original_height, original_width = image_matrix.shape
        inv_scale_factor_y = original_height/new_height
        inv_scale_factor_x = original_width/new_width
    
        # This is an ugly serial operation.
        for new_y in range(new_height):
            for new_x in range(new_width):
                # If you had a color image, you could repeat this with all channels here.
                # Find sub-pixels data:
                old_x = new_x * inv_scale_factor_x
                old_y = new_y * inv_scale_factor_y
                x_fraction = old_x - math.floor(old_x)
                y_fraction = old_y - math.floor(old_y)
    
                # Sample four neighboring pixels:
                left_upper = image_matrix[math.floor(old_y), math.floor(old_x)]
                right_upper = image_matrix[math.floor(old_y), min(image_matrix.shape[1] - 1, math.ceil(old_x))]
                left_lower = image_matrix[min(image_matrix.shape[0] - 1, math.ceil(old_y)), math.floor(old_x)]
                right_lower = image_matrix[min(image_matrix.shape[0] - 1, math.ceil(old_y)), min(image_matrix.shape[1] - 1, math.ceil(old_x))]
    
                # Interpolate horizontally:
                blend_top = (right_upper * x_fraction) + (left_upper * (1.0 - x_fraction))
                blend_bottom = (right_lower * x_fraction) + (left_lower * (1.0 - x_fraction))
                # Interpolate vertically:
                final_blend = (blend_top * y_fraction) + (blend_bottom * (1.0 - y_fraction))
                output_image[new_y, new_x] = final_blend
    
        return output_image
    

    样本重缩放:

    原件: Original Resolution 1280x720

    缩减一半: Half Scale

    扩大了一个季度: 1.25x Scale

        9
  •  1
  •   fabda01    5 年前

    在numpy/SciPy中有任何库可以这样做吗

    当然您可以在没有OpenCV、scikit image或PIL的情况下完成此操作。

    图像大小调整基本上是将每个像素的坐标从原始图像映射到其大小调整后的位置。

    由于图像的坐标必须是整数(将其视为矩阵),如果映射的坐标具有十进制值,则应插值像素值以将其近似为整数位置(例如,获取距离该位置最近的像素称为 Nearest neighbor interpolation ).

    您所需要的只是一个为您执行此插值的函数。SciPy有 interpolate.interp2d .

    您可以使用它来调整numpy数组中的图像大小,例如 arr ,如下所示:

    W, H = arr.shape[:2]
    new_W, new_H = (600,300)
    xrange = lambda x: np.linspace(0, 1, x)
    
    f = interp2d(xrange(W), xrange(H), arr, kind="linear")
    new_arr = f(xrange(new_W), xrange(new_H))
    

    当然,如果图像是RGB,则必须对每个通道执行插值。

    如果你想了解更多,我建议你看 Resizing Images - Computerphile .

        10
  •  -1
  •   Miladfa7    5 年前
    import cv2
    import numpy as np
    
    image_read = cv2.imread('filename.jpg',0) 
    original_image = np.asarray(image_read)
    width , height = 452,452
    resize_image = np.zeros(shape=(width,height))
    
    for W in range(width):
        for H in range(height):
            new_width = int( W * original_image.shape[0] / width )
            new_height = int( H * original_image.shape[1] / height )
            resize_image[W][H] = original_image[new_width][new_height]
    
    print("Resized image size : " , resize_image.shape)
    
    cv2.imshow(resize_image)
    cv2.waitKey(0)