0

I want to stitch a series of images together using the Python Imaging Library. However, the images I want to stitch together are contained in two separate directories. Is PIL able to stitch images under this condition?

I have two series of 10 images stored in two directories - let's call them D1 and D2. I would like to use PIL to stitch Image 1 from D1 with Image 1 from D2, Image 2 from D1 with Image 2 from D2, etc. I have a third directory, D3, in which I would like to save the stitched output images.

I thought the correct way to do this would be to use the code snipped provided by user d3ming in [this example] (Stitching Photos together) and use nested for loops to loop over D1 and D2 to provide input images.

Here is the code that I have currently:

list_im1 = sorted(glob.glob(in_dir_1+"*"))      #make list of first set of images
list_im2 = sorted(glob.glob(in_dir_2+"*"))      #make list of second set of images

def merge_images(file1, file2):
    """Merge two images into one, displayed side by side
    :param file1: path to first image file
    :param file2: path to second image file
    :return: the merged Image object
    """
    image1 = Image.open(file1)
    image2 = Image.open(file2)

    (width1, height1) = image1.size
    (width2, height2) = image2.size

    result_width = width1 + width2
    result_height = max(height1, height2)

    result = Image.new('RGB', (result_width, result_height))
    result.paste(im=image1, box=(0, 0))
    result.paste(im=image2, box=(width1, 0))
    return result
    merged = merge_images(file1, file2) 
    merged.save(out_dir)

for i in in_dir_1:                          #first loop through D1
    for j in in_dir_2:                      #second loop through D2
        merge_images(i, j)

I expected that this code snippet, combined with the nested loop, would run through in_dir_1 (D1), search through the image with the same position in in_dir_2 (D2), and return me a series of 10 stitched images in out_dir (D3). However, my code is not returning any output images at all.

Any help will be greatly appreciated.

Reegan Miranda
  • 2,879
  • 6
  • 43
  • 55
ailsa_naismith
  • 333
  • 2
  • 4
  • 15

1 Answers1

1

Immediate solution is replacing the return statement with Image.save().

list_im1 = sorted(glob.glob(in_dir_1+"*"))      #make list of first set of images
list_im2 = sorted(glob.glob(in_dir_2+"*"))      #make list of second set of images

def merge_images(file1, file2):
    """Merge two images into one, displayed side by side
    :param file1: path to first image file
    :param file2: path to second image file
    """
    global ctr
    image1 = Image.open(file1)
    image2 = Image.open(file2)

    (width1, height1) = image1.size
    (width2, height2) = image2.size

    result_width = width1 + width2
    result_height = max(height1, height2)

    result = Image.new('RGB', (result_width, result_height))
    result.paste(im=image1, box=(0, 0))
    result.paste(im=image2, box=(width1, 0))
    result.save(out_dir + str(ctr) + ".png")
    ctr += 1

ctr = 1

for i in in_dir_1:                          #first loop through D1
    for j in in_dir_2:                      #second loop through D2
        merge_images(i, j)

I would suggest you to use a dynamic output image file path (out_dir), meaning the file path should change with different files. Otherwise same image file would be overwritten over and over as the program goes on.

EDIT:-

If you want each image to be saved distinctly, then you can use a counter (just a number to keep track of which image is being processed).

I will be using a global variable which will increment the value of the variable each time a new image has been processed.

Edited the code accordingly.

EDIT 2:-

Since, each image has it's pair, therefore the total number of images in both the folder will be same. So you can use eval() instead of using a pair of for loops in order to get through that issue.

Just replace:-

for i in in_dir_1:                          
    for j in in_dir_2:                      
        merge_images(i, j)

By:-

for i, x in eval(in_dir_1):
    merge_images(in_dir_1[i], in_dir_2[i])
Vasu Deo.S
  • 1,820
  • 1
  • 11
  • 23
  • Thank you, this suggestion was very useful, and with your solution I am very close to solving the problem! The closest I have got to a dynamic output filepath is `result.save(out_dir + str(image1) + '.png')` , but this creates 3 image files that are subsequently overwritten. Would you recommend using a for loop within the function to save each file separately? – ailsa_naismith Aug 07 '19 at 11:18
  • 1
    @ailsa_naismith Edited the Answer. Now images will be saved as `x.png` (were x is a number) – Vasu Deo.S Aug 07 '19 at 12:43
  • Thank you, this helped! The code executed as it should. I realize I now have a different problem, which is that I output 10 x 10 = 100 images, rather than the 10 stitch images I would like. I realize that this is a separate issue caused by my scripting of the last lines, `for i in in_dir_1: for j in in_dir_2: merge_images(i, j)`, which correctly creates an image for every i and j list combination. Now have to think of an edit that means only the 1st image of in_dir_1 is stitched to 1st image of in_dir_2, 2nd with 2nd, etc. – ailsa_naismith Aug 07 '19 at 16:07
  • @ailsa_naismith Edited the Answer. See if it works now – Vasu Deo.S Aug 07 '19 at 16:35
  • Thanks for your second edit! Using `eval`, I received the following error: `TypeError: eval() arg 1 must be a string, bytes or code object`. However, I was able to produce what I wanted by a very similar code inspired by yours: `for i in range(len(list_im_pic)): merge_images(list_im_pic[i], list_im_so2[i])` – ailsa_naismith Aug 09 '19 at 09:12
  • 1
    @ailsa_naismith Glad, I could help you out!! – Vasu Deo.S Aug 09 '19 at 11:58