Уменьшение размера/масштабирования изображения
Я хотел бы сделать изображение и изменить масштаб изображения, в то время как он представляет собой массив 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, вы должны выполнить интерполяцию для каждого канала.
Если вы хотите понять больше, я предлагаю посмотреть Изменение размера изображений - Компьютерный файл.