YasserKhalil
YasserKhalil

Reputation: 9538

Concatenate muliple images with pillow in python

I have searched for this topic of how to merge or concatenate multiple images using python.

from PIL import Image

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

im1 = Image.open('First.png')
im2 = Image.open('Second.png')
im3 = Image.open('Third.png')
im4 = Image.open('Fourth.png')
get_concat_v().save('concat_v.png')

How can I loop through a folder that has multiple images (Say 9 images) and merge every four images into one image? So the final folder should have three images (the first image would contain 4 images, the second image would contain 4 images, the third image would contain 1 image)

Upvotes: 2

Views: 3717

Answers (2)

CrazyChucky
CrazyChucky

Reputation: 3518

Does this do what you're looking for?

It uses more_itertools.chunked to get image file paths in groups of four, including the final group which may be less than four. I also rewrote your concatenation function to accept any number of images, and expand to fit the widest one, if their widths differ.

from pathlib import Path

from more_itertools import chunked
from PIL import Image


def concat_images(*images):
    """Generate composite of all supplied images."""
    # Get the widest width.
    width = max(image.width for image in images)
    # Add up all the heights.
    height = sum(image.height for image in images)
    composite = Image.new('RGB', (width, height))
    # Paste each image below the one before it.
    y = 0
    for image in images:
        composite.paste(image, (0, y))
        y += image.height
    return composite


if __name__ == '__main__':
    # Define the folder to operate on (currently set to the current
    # working directory).
    images_dir = Path('.')
    # Define where to save the output (shown here, will be in `output`
    # inside the images dir).
    output_dir = images_dir / 'output'
    # Create the output folder, if it doesn't already exist.
    output_dir.mkdir(exist_ok=True)

    # Iterate through the .png files in groups of four, using an index
    # to name the resulting output.
    png_paths = images_dir.glob('*.png')
    for i, paths in enumerate(chunked(png_paths, 4), start=1):
        images = [Image.open(path) for path in paths]
        composite = concat_images(*images)
        composite.save(output_dir / f'{i}.png')

Upvotes: 1

rikyeah
rikyeah

Reputation: 2013

Trying to improve upon the already present answer. You can join 4 images in a folder at a time getting their filenames with os.listdir() and composing every 4 iterations.

from PIL import Image
import os

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

images = []
for i, filename in enumerate(os.listdir("yourdirectory")):
    images.append(Image.open(filename)) # keep track of read image
    if i % 3 == 0: # every 4 images, save a new one
        res = get_concat_v(images[0], images[1], images[2], images[3])
        res.save("somewhere")
        images = []

Upvotes: 0

Related Questions