Skip to content

Concatenare immagini con Python, Pillow

Python

Il cuscino (PIL) può essere utilizzato per concatenare (combinare) più immagini verticalmente e orizzontalmente. Crea uno sfondo con Image.new() e incolla le immagini con Image.paste().

Esistono diversi modi per concatenare immagini di dimensioni diverse.

In questo articolo vengono descritti i casi seguenti.

  • Concatena immagini con la stessa altezza o larghezza
  • Concatena immagini con diverse altezze o larghezze
    • Taglia un’area extra e concatena
    • Crea margini e concatena
    • Ridimensiona e concatena
  • Concatena più immagini contemporaneamente
  • Concatena scelta la stessa immagine

Usa le seguenti due immagini come esempio.

from PIL import Image

im1 = Image.open('data/src/lena.jpg')
im2 = Image.open('data/src/rocket.jpg')

Si presume che il codice di esempio sia un’immagine a colori (mode=”RGB”), ma flusso il flusso è lo stesso per le immagini monocromatiche (mode=”L”).

Per ulteriori informazioni sulla concatenazione delle immagini utilizzando OpenCV e scikit-image, vedere gli articoli seguenti. Per immagini della stessa dimensione, scikit-image è facile da usare. Puoi anche aggiungere un bordo tra le immagini.

Concatena immagini con la stessa altezza o larghezza

Crea uno sfondo con Image.new() e incolla le immagini con Image.paste().

def get_concat_h(im1, im2):
    dst = Image.new('RGB', (im1.width + im2.width, im1.height))
    dst.paste(im1, (0, 0))
    dst.paste(im2, (im1.width, 0))
    return dst

def get_concat_v(im1, im2):
    dst = Image.new('RGB', (im1.width, im1.height + im2.height))
    dst.paste(im1, (0, 0))
    dst.paste(im2, (0, im1.height))
    return dst

get_concat_h(im1, im1).save('data/dst/pillow_concat_h.jpg')
get_concat_v(im1, im1).save('data/dst/pillow_concat_v.jpg')

cuscino in pitone concat h

cuscino in pitone concat v

Taglia un’area extra e concatena

In Image.paste(), l’area fuori dall’intervallo dell’immagine da incollare viene ignorata (tagliata).

Nel caso dell’allineamento orizzontale, generi uno sfondo con un’altezza inferiore, e nel caso dell’allineamento verticale, generi una larghezza inferiore, l’area in eccesso viene tagliata e concatenata.

def get_concat_h_cut(im1, im2):
    dst = Image.new('RGB', (im1.width + im2.width, min(im1.height, im2.height)))
    dst.paste(im1, (0, 0))
    dst.paste(im2, (im1.width, 0))
    return dst

def get_concat_v_cut(im1, im2):
    dst = Image.new('RGB', (min(im1.width, im2.width), im1.height + im2.height))
    dst.paste(im1, (0, 0))
    dst.paste(im2, (0, im1.height))
    return dst

get_concat_h_cut(im1, im2).save('data/dst/pillow_concat_h_cut.jpg')
get_concat_v_cut(im1, im2).save('data/dst/pillow_concat_v_cut.jpg')

cuscino in pitone taglio concat h

cuscino in pitone taglio concat v

Nell’esempio sopra, il bordo superiore o sinistro di ciascuna immagine è allineato. I centri possono anche essere allineati.

def get_concat_h_cut_center(im1, im2):
    dst = Image.new('RGB', (im1.width + im2.width, min(im1.height, im2.height)))
    dst.paste(im1, (0, 0))
    dst.paste(im2, (im1.width, (im1.height - im2.height) // 2))
    return dst

def get_concat_v_cut_center(im1, im2):
    dst = Image.new('RGB', (min(im1.width, im2.width), im1.height + im2.height))
    dst.paste(im1, (0, 0))
    dst.paste(im2, ((im1.width - im2.width) // 2, im1.height))
    return dst

get_concat_h_cut_center(im1, im2).save('data/dst/pillow_concat_h_cut_center.jpg')
get_concat_v_cut_center(im1, im2).save('data/dst/pillow_concat_v_cut_center.jpg')

cuscino in pitone concat h tagliato al centro

cuscino in pitone concat v taglio centro

Crea margini e concatena

Crea margini e concatena originale per evitare che l’immagine venga tagliata.

Crea prima uno sfondo grande. Puoi creare il parametro di qualsiasi margine colore specificando il parametro color di Image.new().

def get_concat_h_blank(im1, im2, color=(0, 0, 0)):
    dst = Image.new('RGB', (im1.width + im2.width, max(im1.height, im2.height)), color)
    dst.paste(im1, (0, 0))
    dst.paste(im2, (im1.width, 0))
    return dst

def get_concat_v_blank(im1, im2, color=(0, 0, 0)):
    dst = Image.new('RGB', (max(im1.width, im2.width), im1.height + im2.height), color)
    dst.paste(im1, (0, 0))
    dst.paste(im2, (0, im1.height))
    return dst

get_concat_h_blank(im1, im2).save('data/dst/pillow_concat_h_blank.jpg')
get_concat_v_blank(im1, im2, (0, 64, 128)).save('data/dst/pillow_concat_v_blank.jpg')

cuscino in pitone concat h vuoto

cuscino in pitone concat v vuoto

Ridimensiona e concatena

Ridimensiona l’immagine in modo che corrisponda alla larghezza o all’altezza e collegale.

Nell’esempio è possibile selezionare se ridimensionare un’immagine grande piccola o ridimensionare un’immagine piccola grande. Fondamentalmente, è meglio ridurre le dimensioni di un’immagine grande a una dimensione inferiore perché la qualità dell’immagine ridotta quando viene ingrandita.

Inoltre, è possibile specificare il filtro per il ricampionamento.

def get_concat_h_resize(im1, im2, resample=Image.BICUBIC, resize_big_image=True):
    if im1.height == im2.height:
        _im1 = im1
        _im2 = im2
    elif (((im1.height > im2.height) and resize_big_image) or
          ((im1.height  im2.height) and not resize_big_image)):
        _im1 = im1.resize((int(im1.width * im2.height / im1.height), im2.height), resample=resample)
        _im2 = im2
    else:
        _im1 = im1
        _im2 = im2.resize((int(im2.width * im1.height / im2.height), im1.height), resample=resample)
    dst = Image.new('RGB', (_im1.width + _im2.width, _im1.height))
    dst.paste(_im1, (0, 0))
    dst.paste(_im2, (_im1.width, 0))
    return dst

def get_concat_v_resize(im1, im2, resample=Image.BICUBIC, resize_big_image=True):
    if im1.width == im2.width:
        _im1 = im1
        _im2 = im2
    elif (((im1.width > im2.width) and resize_big_image) or
          ((im1.width  im2.width) and not resize_big_image)):
        _im1 = im1.resize((im2.width, int(im1.height * im2.width / im1.width)), resample=resample)
        _im2 = im2
    else:
        _im1 = im1
        _im2 = im2.resize((im1.width, int(im2.height * im1.width / im2.width)), resample=resample)
    dst = Image.new('RGB', (_im1.width, _im1.height + _im2.height))
    dst.paste(_im1, (0, 0))
    dst.paste(_im2, (0, _im1.height))
    return dst

get_concat_h_resize(im1, im2).save('data/dst/pillow_concat_h_resize.jpg')
get_concat_v_resize(im1, im2, resize_big_image=False).save('data/dst/pillow_concat_v_resize.jpg')

cuscino in pitone concat h ridimensionato

cuscino in pitone concat v ridimensiona

Concatena più immagini contemporaneamente

È possibile ottenere un’immagine concatenata in cui più immagini sono disposte in fila verticalmente e orizzontalmente utilizzando la funzione sopra definita.

Ad esempio, passare un elenco di PIL.Image e concatenarli verticalmente e orizzontalmente.

def get_concat_h_multi_blank(im_list):
    _im = im_list.pop(0)
    for im in im_list:
        _im = get_concat_h_blank(_im, im)
    return _im

get_concat_h_multi_blank([im1, im2, im1]).save('data/dst/pillow_concat_h_multi_blank.jpg')

cuscino in pitone concat h multi blank

Nell’esempio sopra, la funzione per creare margini. Se vuoi concatenare con altri modi, usa la funzione corrispondente come appropriato.

Quando si riduceno e si dispone più immagini, è meglio ridimensionare prima tutte le immagini alla larghezza o all’altezza finali per evitare il ridimensionamento adeguato e il deterioramento della qualità dell’immagine.

Qui, crea prima uno sfondo grande con Image.new().

def get_concat_h_multi_resize(im_list, resample=Image.BICUBIC):
    min_height = min(im.height for im in im_list)
    im_list_resize = [im.resize((int(im.width * min_height / im.height), min_height),resample=resample)
                      for im in im_list]
    total_width = sum(im.width for im in im_list_resize)
    dst = Image.new('RGB', (total_width, min_height))
    pos_x = 0
    for im in im_list_resize:
        dst.paste(im, (pos_x, 0))
        pos_x += im.width
    return dst

def get_concat_v_multi_resize(im_list, resample=Image.BICUBIC):
    min_width = min(im.width for im in im_list)
    im_list_resize = [im.resize((min_width, int(im.height * min_width / im.width)),resample=resample)
                      for im in im_list]
    total_height = sum(im.height for im in im_list_resize)
    dst = Image.new('RGB', (min_width, total_height))
    pos_y = 0
    for im in im_list_resize:
        dst.paste(im, (0, pos_y))
        pos_y += im.height
    return dst

get_concat_h_multi_resize([im1, im2, im1]).save('data/dst/pillow_concat_h_multi_resize.jpg')
get_concat_v_multi_resize([im1, im2, im1]).save('data/dst/pillow_concat_v_multi_resize.jpg')

cuscino in pitone concat h multi resize

cuscino in pitone concat v multi resize

Anche la funzione per disporre in una piastrella è facile. Passa un elenco 2D di PIL.Image e disponi in riquadri verticalmente e orizzontalmente.

def get_concat_tile_resize(im_list_2d, resample=Image.BICUBIC):
    im_list_v = [get_concat_h_multi_resize(im_list_h, resample=resample) for im_list_h in im_list_2d]
    return get_concat_v_multi_resize(im_list_v, resample=resample)

get_concat_tile_resize([[im1],
                        [im1, im2],
                        [im1, im2, im1]]).save('data/dst/pillow_concat_tile_resize.jpg')

cuscino in pitone concat piastrella ridimensionata

Le comprensioni degli elenchi vengono utilizzate per creare un elenco di immagini ridimensionato e per calcolare la larghezza e l’altezza minima, la larghezza e l’altezza totale.

Concatena scelta la stessa immagine

Se si desidera combinare e utilizzare la stessa immagine verticalmente, è problematico specificarlo nell’elenco 2D, quindi è conveniente preparare una funzione per specificare il numero di ripetizioni.

def get_concat_h_repeat(im, column):
    dst = Image.new('RGB', (im.width * column, im.height))
    for x in range(column):
        dst.paste(im, (x * im.width, 0))
    return dst

def get_concat_v_repeat(im, row):
    dst = Image.new('RGB', (im.width, im.height * row))
    for y in range(row):
        dst.paste(im, (0, y * im.height))
    return dst

def get_concat_tile_repeat(im, row, column):
    dst_h = get_concat_h_repeat(im, column)
    return get_concat_v_repeat(dst_h, row)

im_s = im1.resize((im1.width // 2, im1.height // 2))
get_concat_tile_repeat(im_s, 3, 4).save('data/dst/pillow_concat_tile_repeat.jpg')

ripetitivo delle mattonelle di concat del cuscino del pitone