Thursday, 14 February 2019

Automatisation of figures' creation using Python

Biologists, sometimes are involved in the preparation of field guides for species identification. Arranging many images could be an endless task. Because I am lazy, I always try to automatize the work.

Recently, I had to arrange 60 images in ten arrays of 2x3 (2 columns, three rows). Luckily, I found a code in Python that can do the work for me. The code was written for Evan Rosica, and it can be found here.

Herein, an example of how the code works!

We are going to merge the following images in a matrix of 2x2:




In #1 I am loading the libraries required. Basically, this code use "PIL."
In #2 you need to specify the directory where your images are stored (line 16).
In #3 the most relevant is that you should understand that all images will be resized according to the first image of your directory (line 28). However, you can change it quickly.
In #4 is a loop which will add each image in a sequence. There is not much mystery here.
In #5 I create some boxes and label for my images. I think it is possible to create a loop for this. If you can improve it you are welcome to try!
In #6 The final result is showed and saved if you want (uncomment line 84).

Below the full code

# -*- coding: utf-8 -*-
"""
Created on Thu Oct 20 22:19:44 2018
@author: Irbin B. (Based almost totally on Evan Rosica Code)
"""
#Create a Grid/Matrix of Images
## 1. Import the librearies
import numpy as np
import PIL, os, glob
from PIL import Image, ImageDraw, ImageFont
from math import ceil, floor
## 2. Preliminaries
PATH = r"/Users/Irbin/Downloads/Blog" # Specify the folder where your images are
frame_width = 8000 # in pixels
images_per_row = 2 # change the number of rows
padding = 0 # spacing between images
os.chdir(PATH) # Keep the path of my files
images = sorted(glob.glob("*.JPG")) # sorted images, important if you have the images in a specific order
images = images[:] # it will take all the images in the direcotry
## 3. Resizing the images to standard dimensions
img_width, img_height = Image.open(images[0]).size # the image will be resized to the first one of the folder. You can change it!
sf = (frame_width-(images_per_row-1)*padding)/(images_per_row*img_width) #scaling factor
scaled_img_width = ceil(img_width*sf)
scaled_img_height = ceil(img_height*sf)
number_of_rows = ceil(len(images)/images_per_row)
frame_height = ceil(sf*img_height*number_of_rows)
new_im = Image.new('RGB', (frame_width, frame_height))
i,j=0,0
# 4. Set up the loop which will add the images in sequence
# The loop that will go adding images
for num, im in enumerate(images):
if num%images_per_row==0:
i=0
im = Image.open(im)
im.thumbnail((scaled_img_width,scaled_img_height))
y_cord = (j//images_per_row)*scaled_img_height
new_im.paste(im, (i,y_cord))
print(i, y_cord)
i=(i+scaled_img_width) + padding
j+=1
# 5. Adding labels
font = ImageFont.truetype('/Library/Fonts/Arial Bold.ttf', 400) # Optional (type of font)
box = ImageDraw.Draw(new_im) # It will add a box where a label will be located
## Below are the labels from A to D
A = (0, 0, frame_width/16, frame_height/8)
B = (frame_width/2, 0, frame_width/2 + frame_width/16, frame_height/8)
C = (0, frame_height/2, frame_width/16, frame_height/2 + frame_height/8)
D = (frame_width/2, frame_height/2, frame_width/2 + frame_width/16, frame_height/2 + frame_height/8)
box_wc = np.mean([A[0], A[2]])/2
box_lc = np.mean([A[1], A[3]])/2
box.rectangle(A, outline='black', fill='white')
box.rectangle(B, outline='black', fill='white')
box.rectangle(C, outline='black', fill='white')
box.rectangle(D, outline='black', fill='white')
box.text((A[0] + box_wc, A[1] + box_lc),
"A", font=font, fill='black')
box.text((B[0] + box_wc, B[1] + box_lc),
"B", font=font, fill='black')
box.text((C[0] + box_wc, C[1] + box_lc),
"C", font=font, fill='black')
box.text((D[0] + box_wc, D[1] + box_lc),
"D", font=font, fill='black')
# 6. Look and save
new_im.show()
#new_im.save("Test.png", "PNG", quality=80, optimize=True, progressive=True)
view raw Merge_Images.py hosted with ❤ by GitHub
And here, the final result.



As you can see this code can help us to save time if we need to arrange too many images, even if you are writing papers that demand merging a lot of figures.