Изменение размера прямоугольного изображения на квадрат, сохранение коэффициента и заполнение фона черным

Я пытаюсь изменить размер серии изображений в градациях серого, которые имеют размер 256 x N пикселей (N изменяется, но всегда ≤256).

Мое намерение состоит в том, чтобы уменьшить изображения.

При изменении размера должно получиться квадратное изображение (1:1) с:

  • измененное изображение по центру по вертикали
  • соотношение сторон сохраняется
  • оставшиеся пиксели отображаются чёрным

Визуально это будет желаемый результат:

enter image description here

Я попытался создать матрицу с нулевыми нулями с целевым размером (например, 200 x 200), но не смог вставить измененное изображение в его вертикальный центр.

Любые предложения с использованием cv2, PIL или numpy приветствуются.

Ответ 1

Вы можете использовать Pillow для этого:

Код:

from PIL import Image

def make_square(im, min_size=256, fill_color=(0, 0, 0, 0)):
    x, y = im.size
    size = max(min_size, x, y)
    new_im = Image.new('RGBA', (size, size), fill_color)
    new_im.paste(im, int(((size - x) / 2), int((size - y) / 2)))
    return new_im

Тестовый код:

test_image = Image.open('hLarp.png')
new_image = make_square(test_image)
new_image.show()

Для белого фона вы можете сделать:

new_image = make_square(test_image, fill_color=(255, 255, 255, 0))

Результат:

enter image description here

Ответ 2

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

from PIL import Image

def black_background_thumbnail(path_to_image, thumbnail_size=(200,200)):
    background = Image.new('RGBA', thumbnail_size, "black")    
    source_image = Image.open(path_to_image).convert("RGBA")
    source_image.thumbnail(thumbnail_size)
    (w, h) = source_image.size
    background.paste(source_image, ((thumbnail_size[0] - w) / 2, (thumbnail_size[1] - h) / 2 ))
    return background

if __name__ == '__main__':
    img = black_background_thumbnail('hLARP.png')
    img.save('tmp.jpg')
    img.show()

Ответ 3

from PIL import Image

def reshape(image):
    '''
    Reshapes the non-square image by pasting
    it to the centre of a black canvas of size
    n*n where n is the biggest dimension of
    the non-square image. 
    '''
    old_size = image.size
    max_dimension, min_dimension = max(old_size), min(old_size)
    desired_size = (max_dimension, max_dimension)
    position = int(max_dimension/2) - int(min_dimension/2) 
    blank_image = Image.new("RGB", desired_size, color='black')
    if image.height<image.width:
        blank_image.paste(image, (0, position))
    else:
        blank_image.paste(image, (position, 0))
    return blank_image