Skip to content

Instantly share code, notes, and snippets.

@jdhao
Last active June 15, 2023 04:12
Show Gist options
  • Save jdhao/f8422980355301ba30b6774f610484f2 to your computer and use it in GitHub Desktop.
Save jdhao/f8422980355301ba30b6774f610484f2 to your computer and use it in GitHub Desktop.
this script will resize and pad an image to desired square size and keep its aspect ratio unchanged. Before running the script, please change the size and image path to valid value.
from PIL import Image, ImageOps
import cv2
desired_size = 368
im_pth = "/home/jdhao/test.jpg"
# im = Image.open(im_pth)
# old_size = im.size # old_size[0] is in (width, height) format
# ratio = float(desired_size)/max(old_size)
# new_size = tuple([int(x*ratio) for x in old_size])
## using thumbnai() or resize() method to resize the input image and keep its aspect ratio
# im.thumbnail(new_size, Image.ANTIALIAS)
# im = im.resize(new_size, Image.ANTIALIAS)
## create a new square image with desired size and paste the resized image onto it.
# new_im = Image.new("RGB", (desired_size, desired_size))
# new_im.paste(im, ((desired_size-new_size[0])//2,
# (desired_size-new_size[1])//2))
## or we can expand the resized image by adding borders to its 4 side
# delta_w = desired_size - new_size[0]
# delta_h = desired_size - new_size[1]
# padding = (delta_w//2, delta_h//2, delta_w-(delta_w//2), delta_h-(delta_h//2))
# print(padding)
# new_im = ImageOps.expand(im, padding, fill="black")
# new_im.show()
## opencv has copyMakeBorder() method which is handy for making borders
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[1], new_size[0]))
delta_w = desired_size - new_size[1]
delta_h = desired_size - new_size[0]
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()
@Relative0
Copy link

Relative0 commented May 17, 2019

Hi jdhao. Thanks for the code, pretty cool. I uncommented the part to draw a "black" box around the image. It didn't work right away and what I did is I changed new_size to not be multiplied by ratio as one would then have that x*ratio = desired_size which gives that new_size = desired_size. So the change is: new_size = tuple([int(x) for x in old_size]).

That is I just changed int(x*ratio) to be int(x). Now as long as the desired size is LARGER than the input image size, a black box should be drawn around it.

I removed the comments in the code as commenting via this forum the comments came up in large black bold. Uncommented and corrected code for that part is then:

from PIL import Image, ImageOps
import cv2

desired_size = 500
im_pth = "TestImage.jpg"

im = Image.open(im_pth)
old_size = im.size  

ratio = float(desired_size)/max(old_size)

new_size = tuple([int(x) for x in old_size])

im = im.resize(new_size, Image.ANTIALIAS)

new_im = Image.new("RGB", (desired_size, desired_size))
new_im.paste(im, ((desired_size-new_size[0])//2,
                      (desired_size-new_size[1])//2))

delta_w = desired_size - new_size[0]
delta_h = desired_size - new_size[1]
padding = (delta_w//2, delta_h//2, delta_w-(delta_w//2), delta_h-(delta_h//2))
print(padding)
new_im = ImageOps.expand(im, padding, fill="black")
new_im.show()

@pakshi10
Copy link

while running the code i get this error:
Traceback (most recent call last):
File "padding.py", line 7, in
old_size = im.shape[:2] # old_size is in (height, width) format
AttributeError: 'NoneType' object has no attribute 'shape'

any ideas whats wrong?

You have to paas single image path not the path of whole folder.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment