Уменьшение размера/масштабирования изображения

Я хотел бы сделать изображение и изменить масштаб изображения, в то время как он представляет собой массив numpy.

Например, у меня есть этот образ бутылки кока-колы: бутылка-1

Это переводит в массив с множеством чисел (528, 203, 3) и я хочу изменить его размер, чтобы сказать размер этого второго изображения: bottle-2

Которая имеет форму (140, 54, 3).

Как изменить размер изображения на определенную фигуру, сохраняя при этом исходное изображение? Другие ответы предлагают удалить все остальные или третьи строки, но то, что я хочу сделать, в основном уменьшает изображение, как вы могли бы с помощью редактора изображений, но в коде python. Есть ли библиотеки для этого в numpy/SciPy?

Ответы

Ответ 1

Да, вы можете установить 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 представляет собой массив numpy, содержащий измененное изображение. Важным аспектом является параметр interpolation: существует несколько способов изменения размера изображения. Тем более, что вы уменьшаете изображение, а размер исходного изображения не кратен размеру измененного изображения. Возможные схемы интерполяции:

  • INTER_NEAREST - интерполяция ближайшего соседа
  • INTER_LINEAR - билинейная интерполяция (используется по умолчанию)
  • INTER_AREA - INTER_AREA с использованием отношения области пикселей. Это может быть предпочтительный метод для прореживания изображения, поскольку он дает результаты без муара. Но когда изображение масштабируется, оно похоже на метод INTER_NEAREST.
  • INTER_CUBIC - бикубическая интерполяция в окрестности 4x4 пикселей
  • INTER_LANCZOS4 - интерполяция INTER_LANCZOS4 в окрестности 8x8 пикселей

Как и в большинстве опций, нет "лучшего" варианта в том смысле, что для каждой схемы изменения размера существуют сценарии, в которых одна стратегия может быть предпочтительнее другой.

Ответ 2

Хотя для этого можно использовать только numpy, операция не является встроенной. Тем не менее, вы можете использовать scikit-image (который построен на NumPy), чтобы сделать этот вид манипуляции изображения.

Документация по масштабированию Scikit-Image здесь.

Например, вы можете сделать следующее с вашим изображением:

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

Это позаботится о таких вещах, как интерполяция, сглаживание и т.д. для вас.

Ответ 3

Для тех, кто приезжает сюда из Google и ищет быстрый способ сокращения изображений в массивах numpy для использования в приложениях машинного обучения, здесь используется сверхбыстрый метод (адаптированный из здесь). Этот метод работает только тогда, когда входные измерения кратны выходным измерениям.

В следующих примерах уменьшен размер от 128х128 до 64х64 (это можно легко изменить).

Каналы последнего заказа

# 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)

Этот метод использует эквивалент максимального пула. Это самый быстрый способ сделать это, что я нашел.

Ответ 4

imresize() SciPy imresize() был другим методом изменения размера, но он будет удален, начиная с SciPy v 1.3.0. SciPy ссылается на метод изменения размера изображения PIL: Image.resize(size, resample=0)

size - Запрашиваемый размер в пикселях в виде двух кортежей: (ширина, высота).
resample - дополнительный фильтр передискретизации. Это может быть 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.Image.resize

Ответ 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)

Ответ 6

  Есть ли библиотеки для этого в numpy/SciPy

Конечно. Вы можете сделать это без OpenCV, scikit-image или PIL.

Изменение размера изображения в основном отображает координаты каждого пикселя от исходного изображения до его положения с измененным размером.

Поскольку координаты изображения должны быть целыми числами (представьте, что это матрица), если отображаемая координата имеет десятичные значения, необходимо интерполировать значение пикселя, чтобы приблизить его к целочисленной позиции (например, известно, что ближайший пиксель к этой позиции известен как интерполяция ближайшего соседа).

Все, что вам нужно, это функция, которая выполняет эту интерполяцию за вас. У SciPy есть interpolate.interp2d.

Вы можете использовать его для изменения размера изображения в массиве, скажем, 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, вы должны выполнить интерполяцию для каждого канала.

Если вы хотите понять больше, я предлагаю посмотреть Изменение размера изображений - Компьютерный файл.