When we are using convolutional neural networks, most of the time, we need to fix the input image size to feed it to the network. The usual practice is to resize the input image to the given size (the image aspect ratio is no longer kept) and then crop a fixed size patch randomly from the resized image. This practice may work well for image classification where fine details may not be necessary. But for Image retrieval, we want to keep the image aspect ration unchanged. In this post, I will summarize ways to resize an image to square shape with padding and keep its aspect ratio.
The main idea is to first resize the input image so that its maximum size equals to the given size. Then we pad the resized image to make it square. A number of packages in Python can easily achieves this.
PIL is a popular image processing package in Python. We can use either
Image module or the
ImageOps module to achieve what we want.
Resize and pad with
First we create a blank square image, then we paste the resized image on it to form a new image. The code is:
from PIL import Image, ImageOps desired_size = 368 im_pth = "/home/jdhao/test.jpg" im = Image.open(im_pth) old_size = im.size # old_size is in (width, height) format ratio = float(desired_size)/max(old_size) new_size = tuple([int(x*ratio) for x in old_size]) # use thumbnail() or resize() method to resize the input image # thumbnail is a in-place operation # im.thumbnail(new_size, Image.ANTIALIAS) im = im.resize(new_size, Image.ANTIALIAS) # create a new image and paste the resized on it new_im = Image.new("RGB", (desired_size, desired_size)) new_im.paste(im, ((desired_size-new_size)//2, (desired_size-new_size)//2)) new_im.show()
Resize and pad with
ImageOps module has a
expand which will add borders to the 4 side of an image. We need to calculate the padding length in 4 side of the resized image before applying this method.
delta_w = desired_size - new_size delta_h = desired_size - new_size padding = (delta_w//2, delta_h//2, delta_w-(delta_w//2), delta_h-(elta_h//2)) new_im = ImageOps.expand(im, padding) new_im.show()
In OpenCV, we have
copyMakeBorder which is handy in making borders. The full code to resize and pad an image is as follows:
import cv2 desired_size = 368 im_pth = "/home/jdhao/test.jpg" im = cv2.imread(im_pth) old_size = im.shape[:2] # old_size is in (height, width) format ratio = float(desired_size)/max(old_size) new_size = tuple([int(x*ratio) for x in old_size]) # new_size should be in (width, height) format im = cv2.resize(im, (new_size, new_size)) delta_w = desired_size - new_size delta_h = desired_size - new_size top, bottom = delta_h//2, delta_h-(delta_h//2) left, right = delta_w//2, delta_w-(delta_w//2) color = [0, 0, 0] new_im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) cv2.imshow("image", new_im) cv2.waitKey(0) cv2.destroyAllWindows()
I have upload the whole script to GitHub and you can download it here.
License CC BY-NC-ND 4.0