数字缩放/重新缩放图像

我想采取一个图像和改变图像的比例,而它是一个数字数组。

例如,我有一个可口可乐瓶的图片: 一瓶

转换成一个形状为 (528, 203, 3)的数组,我想调整它的大小来表示第二张图片的大小: 第二瓶

它有一个 (140, 54, 3)的形状。

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

346539 次浏览

是的,您可以安装 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是一个包含原始图像的数字数组,而 res是一个包含 调整尺寸图像的数字数组。一个重要的方面是 interpolation参数: 有几种方法可以调整图像的大小。特别是因为你缩小了图像,并且原始图像的大小是 没有缩小图像大小的倍数。可能的插值模式如下:

  • 近邻取样插值
  • INTER_LINEAR-a 双线性插值(默认使用)
  • 使用像素区域关系的重采样。它可能是图像抽取的首选方法,因为它给莫尔’免费 但是当图像放大时,它类似于 INTER_NEAREST法。
  • 双三次插值超过4 × 4像素的邻居
  • INTER_LANCZOS4-8x8像素邻域上的 Lanczos 插值

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

虽然可以单独使用 numpy 来完成这项工作,但是这个操作并不是内置的。也就是说,您可以使用 scikit-image(构建于 numpy 之上)来进行这种图像操作。

Scikit-图像重新缩放文档是 给你

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

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

这将照顾的事情,如插值,反锯齿,等为您。

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

Size -请求的大小(以像素为单位)为2元组: (width,height)。
重新采样 -一个可选的重新采样过滤器。这可以是 PIL.Image.NEAREST (使用最近的邻居) ,PIL.Image.BILINEAR (线性插值) ,PIL.Image.BICUBIC (立方体样条插值) ,或者 PIL.Image.LANCZOS (高质量的下采样过滤器)。如果省略,或者图像具有模式“1”或“ P”,则设置为 PIL.Image.NEAREST。

链接: Https://pillow.readthedocs.io/en/3.1.x/reference/image.html#pil.image 图像调整大小

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)

对于那些来自谷歌的人来说,他们正在寻找一种快速的方法来降低机器学习应用程序中使用的 numpy阵列中的图像采样,这里有一个超级快速的方法(改编自 给你)。此方法只有在输入维度是输出维度的倍数时才有效。

下面的示例从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改为 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)

这个方法使用了相当于 max 池的方法,这是我所发现的最快的方法。

在 numpy/SciPy 中是否有这样做的库

当然,没有 OpenCV,scikit-image 或 PIL,你也可以做到这一点。

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

因为一个图像的坐标必须是整数(把它想象成一个矩阵) ,如果映射的坐标有十进制值,你应该插值像素值来近似它的整数位置(例如,得到最接近该位置的像素称为 近邻取样插值)。

所有你需要的是一个函数,为您做这个插值。

您可以使用它来调整数字数组(比如 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,您必须为每个通道执行插值。

如果你想了解更多,我建议看 调整图像大小-计算机爱好者

如果有人想在 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)]

示例用法: 将(30x30)图像的大小调整为(100x200) :

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

这可以缩小/缩放图像,并且可以很好地使用数字数组。

下采样的一行数解(乘以2) :

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

以及 向上取样(by 2) :

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

注意,此方法只允许整数调整大小(例如,2x 但不是1.5 x)

对于那些想要调整(插值)一批 numpy 数组的人来说,pytch 提供了一个更快的函数名 Torch.nn.Functional.interpolate,只要记住首先使用 np.transose 将通道从 batchxWxHx3更改为 batchx3xWxH。

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

  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