Добавление границ к изображению с использованием python
У меня есть большое количество изображений фиксированного размера (скажем, 500 * 500). Я хочу написать python script, который изменит их размер до фиксированного размера (скажем, 800 * 800), но сохранит исходное изображение в центре и заполнит лишнюю область фиксированным цветом (например, черный).
Я использую PIL. Теперь я могу изменить размер изображения с помощью функции resize
, но это изменит соотношение сторон. Есть ли способ сделать это?
Ответы
Ответ 1
Вы можете создать новое изображение с требуемым новым размером и вставить старое изображение в центр, а затем сохранить его. Если вы хотите, вы можете перезаписать исходное изображение (вы уверены?? O)
import Image
old_im = Image.open('someimage.jpg')
old_size = old_im.size
new_size = (800, 800)
new_im = Image.new("RGB", new_size) ## luckily, this is already black!
new_im.paste(old_im, ((new_size[0]-old_size[0])/2,
(new_size[1]-old_size[1])/2))
new_im.show()
# new_im.save('someimage.jpg')
Ответ 2
Да, есть.
Сделайте что-то вроде этого:
import Image, ImageOps
ImageOps.expand(Image.open('original-image.png'),border=300,fill='black').save('imaged-with-border.png')
Вы можете написать то же самое в нескольких строках:
import Image, ImageOps
img = Image.open('original-image.png')
img_with_border = ImageOps.expand(img,border=300,fill='black')
img_with_border.save('imaged-with-border.png')
И вы говорите, что у вас есть список изображений. Затем вы должны использовать цикл для обработки всех из них:
import Image, ImageOps
for i in list-of-images:
img = Image.open(i)
img_with_border = ImageOps.expand(img,border=300,fill='black')
img_with_border.save('bordered-%s' % i)
Ответ 3
В качестве альтернативы, если вы используете OpenCV, у них есть функция под названием copyMakeBorder
, которая позволяет добавлять дополнения к любому из стороны изображения. Помимо сплошных цветов, у них также есть несколько интересных вариантов для фантастических границ, таких как отражение или расширение изображения.
import cv2
img = cv2.imread('image.jpg')
color = [101, 52, 152] # 'cause purple!
# border widths; I set them all to 150
top, bottom, left, right = [150]*4
img_with_border = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)
![Примеры результатов функции cv2.copyMakeBorder]()
Источники: Учебное пособие по OpenCV и
OpenCV 3.1.0 Документы для copyMakeBorder
Ответ 4
Важно рассмотреть старое измерение, новое измерение и их различие. Если разница нечетная (даже не), вам нужно будет указать несколько разные значения для границ слева, сверху, вправо и внизу.
Предположим, что старое измерение - ow, oh и новое - nw, nh.
Итак, это будет ответ:
import Image, ImageOps
img = Image.open('original-image.png')
deltaw=nw-ow
deltah=nh-oh
ltrb_border=(deltaw/2,deltah/2,deltaw-(deltaw/2),deltah-(deltah/2))
img_with_border = ImageOps.expand(img,border=ltrb_border,fill='black')
img_with_border.save('imaged-with-border.png')
Ответ 5
Метод PIL crop
может фактически справиться с этим для вас, используя числа, которые находятся за пределами ограничивающей рамки исходного изображения, хотя это явно не указано в документация. Отрицательные числа для левого и верхнего будут добавлять черные пиксели к этим краям, в то время как числа, превышающие исходную ширину и высоту для правого и нижнего, будут добавлять черные пиксели к этим краям.
Этот код учитывает нечетные размеры пикселей:
from PIL import Image
with Image.open('/path/to/image.gif') as im:
old_size = im.size
new_size = (800, 800)
if new_size > old_size:
# Set number of pixels to expand to the left, top, right,
# and bottom, making sure to account for even or odd numbers
if old_size[0] % 2 == 0:
add_left = add_right = (new_size[0] - old_size[0]) // 2
else:
add_left = (new_size[0] - old_size[0]) // 2
add_right = ((new_size[0] - old_size[0]) // 2) + 1
if old_size[1] % 2 == 0:
add_top = add_bottom = (new_size[1] - old_size[1]) // 2
else:
add_top = (new_size[1] - old_size[1]) // 2
add_bottom = ((new_size[1] - old_size[1]) // 2) + 1
left = 0 - add_left
top = 0 - add_top
right = old_size[0] + add_right
bottom = old_size[1] + add_bottom
# By default, the added pixels are black
im = im.crop((left, top, right, bottom))
Вместо 4-кортежей вместо этого вы можете использовать 2-кортеж, чтобы добавить одинаковое количество пикселей слева/справа и сверху/снизу, или 1-кортеж, чтобы добавить одинаковое количество пикселей со всех сторон.
Ответ 6
Вы можете загрузить изображение scipy.misc.imread
в виде массива numpy. Затем создайте массив с желаемым фоном с numpy.zeros((height, width, channels))
и вставьте изображение в нужное место:
import numpy as np
import scipy.misc
im = scipy.misc.imread('foo.jpg', mode='RGB')
height, width, channels = im.shape
# make canvas
im_bg = np.zeros((height, width, channels))
im_bg = (im_bg + 1) * 255 # e.g., make it white
# Your work: Compute where it should be
pad_left = ...
pad_top = ...
im_bg[pad_top:pad_top + height,
pad_left:pad_left + width,
:] = im
# im_bg is now the image with the background.