В Python, Python Image Library 1.1.6, как я могу расширить холст без изменения размера?

Я, вероятно, ищу в руководстве не то, что нужно, но я хочу взять объект изображения и расширить его без изменения размера (растяжения / сжатия) исходного изображения.

Пример с игрушкой: представьте себе синий прямоугольник 200 x 100, затем я выполняю некоторую операцию, и у меня есть новый объект изображения 400 x 300, состоящий из белого фона, на котором лежит синий прямоугольник 200 x 100. Бонус, если я могу контролировать, в каком направлении это расширяется, или новый цвет фона и т. Д.

По сути, у меня есть изображение, к которому я буду добавлять итеративно, и я не знаю, какого размера он будет в самом начале.

Я полагаю, что я мог бы взять оригинальный объект, сделать новый, немного больший объект, вставить туда оригинал, нарисовать немного больше, а затем повторить. Кажется, что это может быть вычислительно дорого. Однако я подумал, что для этого найдется функция, так как я предполагаю, что это обычная операция. Возможно, я ошибся.

3 ответа

Решение

Функция ImageOps.expand расширяет изображение, но добавляет одинаковое количество пикселей в каждом направлении.

Лучший способ - просто сделать новое изображение и вставить:

newImage = Image.new(mode, (newWidth,newHeight))
newImage.paste(srcImage, (x1,y1,x1+oldWidth,y1+oldHeight))

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

На основании промежуточного ответа:

#!/usr/bin/env python

from PIL import Image
import math


def resize_canvas(old_image_path="314.jpg", new_image_path="save.jpg",
                  canvas_width=500, canvas_height=500):
    """
    Resize the canvas of old_image_path.

    Store the new image in new_image_path. Center the image on the new canvas.

    Parameters
    ----------
    old_image_path : str
    new_image_path : str
    canvas_width : int
    canvas_height : int
    """
    im = Image.open(old_image_path)
    old_width, old_height = im.size

    # Center the image
    x1 = int(math.floor((canvas_width - old_width) / 2))
    y1 = int(math.floor((canvas_height - old_height) / 2))

    mode = im.mode
    if len(mode) == 1:  # L, 1
        new_background = (255)
    if len(mode) == 3:  # RGB
        new_background = (255, 255, 255)
    if len(mode) == 4:  # RGBA, CMYK
        new_background = (255, 255, 255, 255)

    newImage = Image.new(mode, (canvas_width, canvas_height), new_background)
    newImage.paste(im, (x1, y1, x1 + old_width, y1 + old_height))
    newImage.save(new_image_path)

resize_canvas()

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

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

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

Протестировано с файлами PNG в режиме P.

Закодированная отладка final.show() и breakдля тестирования. Удалить строки и хэштег на final.save(...) зациклить и сохранить.

Можно было параметризовать соотношение холста и повысить гибкость, но это послужило моей цели.

"""
Resize ... and reconfigures. images in a specified directory

Use case:  Images of varying size, need to be enlarged to exaxtly 1200 x 1200
"""
import os
import glob

from PIL import Image

# Source directory plus Glob file reference (Windows)
source_path = os.path.join('C:', os.sep, 'path', 'to', 'source', '*.png')

# List of UNC Image File paths
images = glob.glob(source_path)

# Destination directory of modified image (Windows)
destination_path = os.path.join('C:', os.sep, 'path', 'to', 'destination')

for image in images:
    
    original = Image.open(image)

    # Retain original attributes (ancillary chunks)
    info = original.info
    
    # Retain original mode
    mode = original.mode

    # Retain original palette
    if original.palette is not None:
        palette = original.palette.getdata()[1]
    else:
        palette = False

    # Match original aspect ratio
    dimensions = original.getbbox()

    # Identify destination image background color
    if 'transparency' in info.keys():
        background = original.info['transparency']
    else:
        # Image does not have transparency set
        print(image)
        background = (64)

    # Get base filename and extension for destination
    filename, extension = os.path.basename(image).split('.')
    
    # Calculate matched aspect ratio
    if dimensions[2] > dimensions[3]:
        width = int(1200)
        modifier = width / dimensions[2]
        length = int(dimensions[3] * modifier)
    elif dimensions[3] > dimensions[2]:
        length = int(1200)
        modifier = length / dimensions[3]
        width = int(dimensions[2] * modifier)
    else:
        width, length = (1200, 1200)
    
    size = (width, length)

    # Set desired final image size
    canvas = (1200, 1200)
    
    # Calculate center position
    position = (
        int((1200 - width)/2),
        int((1200 - length)/2),
        int((1200 - width)/2) + width,
        int((1200 - length)/2) + length
    )

    # Enlarge original image proportionally
    resized = original.resize(size, Image.LANCZOS)

    # Then create sized canvas
    final = Image.new(mode, canvas, background)

    # Replicate original properties
    final.info = info

    # Replicate original palatte
    if palette:
        final.putpalette(palette)

     # Cemter paste resized image to final canvas
    final.paste(resized, position)

    # Save final image to destination directory
    final.show()

    #final.save("{}\\{}.{}".format(destination_path, filename, extension))

    break
Другие вопросы по тегам