33
votes

I'm trying to resize a batch of grayscale images that are 256 x N pixels (N varies, but is always ≤256).

My intention is to downscale the images.

The resize would have to output a square (1:1) image, with:

  • resized image centered vertically
  • aspect ratio maintained
  • remaining pixels rendered black

Visually this would be the desired result:

enter image description here

I have tried creating a numpy zeroes matrix with the target size (e.g. 200 x 200) but have not been able to paste the resized image into its vertical center.

Any suggestions using cv2, PIL or numpy are welcome.

4

4 Answers

45
votes

You can use Pillow to accomplish that:

Code:

from PIL import Image

def make_square(im, min_size=256, fill_color=(0, 0, 0, 0)):
    x, y = im.size
    size = max(min_size, x, y)
    new_im = Image.new('RGBA', (size, size), fill_color)
    new_im.paste(im, (int((size - x) / 2), int((size - y) / 2)))
    return new_im

Test Code:

test_image = Image.open('hLarp.png')
new_image = make_square(test_image)
new_image.show()

For a white background you can do:

new_image = make_square(test_image, fill_color=(255, 255, 255, 0))

Result:

enter image description here

8
votes

Here is a code that solve your question with OPENCV module (using NUMPY module too)

#Importing modules opencv + numpy
import cv2
import numpy as np

#Reading an image (you can use PNG or JPG)
img = cv2.imread("image.png")

#Getting the bigger side of the image
s = max(img.shape[0:2])

#Creating a dark square with NUMPY  
f = np.zeros((s,s,3),np.uint8)

#Getting the centering position
ax,ay = (s - img.shape[1])//2,(s - img.shape[0])//2

#Pasting the 'image' in a centering position
f[ay:img.shape[0]+ay,ax:ax+img.shape[1]] = img

#Showing results (just in case) 
cv2.imshow("IMG",f)
#A pause, waiting for any press in keyboard
cv2.waitKey(0)

#Saving the image
cv2.imwrite("img2square.png",f)
cv2.destroyAllWindows()
3
votes

PIL has the thumbnail method which will scale keeping the aspect ratio. From there you just need to paste it centered onto your black background rectangle.

from PIL import Image

def black_background_thumbnail(path_to_image, thumbnail_size=(200,200)):
    background = Image.new('RGBA', thumbnail_size, "black")    
    source_image = Image.open(path_to_image).convert("RGBA")
    source_image.thumbnail(thumbnail_size)
    (w, h) = source_image.size
    background.paste(source_image, ((thumbnail_size[0] - w) / 2, (thumbnail_size[1] - h) / 2 ))
    return background

if __name__ == '__main__':
    img = black_background_thumbnail('hLARP.png')
    img.save('tmp.jpg')
    img.show()
1
votes
from PIL import Image

def reshape(image):
    '''
    Reshapes the non-square image by pasting
    it to the centre of a black canvas of size
    n*n where n is the biggest dimension of
    the non-square image. 
    '''
    old_size = image.size
    max_dimension, min_dimension = max(old_size), min(old_size)
    desired_size = (max_dimension, max_dimension)
    position = int(max_dimension/2) - int(min_dimension/2) 
    blank_image = Image.new("RGB", desired_size, color='black')
    if image.height<image.width:
        blank_image.paste(image, (0, position))
    else:
        blank_image.paste(image, (position, 0))
    return blank_image