Add padding to images to get them into the same shape

105,679

Solution 1

You can use:

image = cv2.copyMakeBorder(src, top, bottom, left, right, borderType)

Where src is your source image and top, bottom, left, right are the padding around the image.

You can use max(sizes) - size value of the image in a while loop to add the padding to each image. The bordertype can be one of these:

  • cv2.BORDER_CONSTANT
  • cv2.BORDER_REFLECT
  • cv2.BORDER_REFLECT_101
  • cv2.BORDER_DEFAULT
  • cv2.BORDER_REPLICATE
  • cv2.BORDER_WRAP

cv2.copyMakeBorder tutorial

Solution 2

Here is another way to do that in Python/OpenCV/Numpy. It uses Numpy slicing to copy the input image into a new image of the desired output size and a given offset. Here I compute the offset to do center padding. I think this is easier to do using width, height, xoffset, yoffset, rather than how much to pad on each side.

Input:

enter image description here

import cv2
import numpy as np

# read image
img = cv2.imread('lena.jpg')
old_image_height, old_image_width, channels = img.shape

# create new image of desired size and color (blue) for padding
new_image_width = 300
new_image_height = 300
color = (255,0,0)
result = np.full((new_image_height,new_image_width, channels), color, dtype=np.uint8)

# compute center offset
x_center = (new_image_width - old_image_width) // 2
y_center = (new_image_height - old_image_height) // 2

# copy img image into center of result image
result[y_center:y_center+old_image_height, 
       x_center:x_center+old_image_width] = img

# view result
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

# save result
cv2.imwrite("lena_centered.jpg", result)

enter image description here

Solution 3

Like this (Padding is called borders on openCV):

BLUE = [255,255,255]
constant= cv2.copyMakeBorder(image.copy(),10,10,10,10,cv2.BORDER_CONSTANT,value=BLUE)

And blue can become white even

source: https://docs.opencv.org/3.4/da/d0c/tutorial_bounding_rects_circles.html

Solution 4

try to use this function:

from PIL import Image, ImageOps


def padding(img, expected_size):
    desired_size = expected_size
    delta_width = desired_size - img.size[0]
    delta_height = desired_size - img.size[1]
    pad_width = delta_width // 2
    pad_height = delta_height // 2
    padding = (pad_width, pad_height, delta_width - pad_width, delta_height - pad_height)
    return ImageOps.expand(img, padding)


def resize_with_padding(img, expected_size):
    img.thumbnail((expected_size[0], expected_size[1]))
    # print(img.size)
    delta_width = expected_size[0] - img.size[0]
    delta_height = expected_size[1] - img.size[1]
    pad_width = delta_width // 2
    pad_height = delta_height // 2
    padding = (pad_width, pad_height, delta_width - pad_width, delta_height - pad_height)
    return ImageOps.expand(img, padding)


if __name__ == "__main__":
    img = Image.open("./demo.jpg")
    print(img)
    img = resize_with_padding(img, (500, 400))
    print(img.size)
    img.show()
    img.save("resized_img.jpg")

Raw image

After resizing with padding

see https://gist.github.com/BIGBALLON/cb6ab73f6aaaa068ab6756611bb324b2

Solution 5

As I do not see an accepted answer, and also the fact that one has to determine the top, bottom, left, right of the function, I have bellow what worked for me easily. Taken from: https://jdhao.github.io/2017/11/06/resize-image-to-square-with-padding/

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[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()
Share:
105,679
vincent
Author by

vincent

Updated on November 15, 2021

Comments

  • vincent
    vincent over 2 years

    l have a set of images of different sizes (45,50,3), (69,34,3), (34,98,3). l want to add padding to these images as follows:

    Take the max width and length of the whole images then put the image in that size

    import os
    import glob
    import cv2
    
    input_path="/home/images"
    os.chdir(indput_path)
    images=glob.glob("*.png")
    Length=[]
    Width=[]
    for img in images:
        img=cv2.imread(img)
        width,length=img.shape[0:2]
        Length.append(length)
        Width.append(width)
    W=max(Width)
    L=max(Length)
    

    How can l add padding in opencv so that all the images will have the same size? In the example l gave the images will get the shape of (69,98,3)