Skip to content

Instantly share code, notes, and snippets.

@IdeaKing
Last active February 1, 2024 16:18
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IdeaKing/11cf5e146d23c5bb219ba3508cca89ec to your computer and use it in GitHub Desktop.
Save IdeaKing/11cf5e146d23c5bb219ba3508cca89ec to your computer and use it in GitHub Desktop.
Resize image with padding using CV2
import cv2
from typing import Tuple
def resize_with_pad(image: np.array,
new_shape: Tuple[int, int],
padding_color: Tuple[int] = (255, 255, 255)) -> np.array:
"""Maintains aspect ratio and resizes with padding.
Params:
image: Image to be resized.
new_shape: Expected (width, height) of new image.
padding_color: Tuple in BGR of padding color
Returns:
image: Resized image with padding
"""
original_shape = (image.shape[1], image.shape[0])
ratio = float(max(new_shape))/max(original_shape)
new_size = tuple([int(x*ratio) for x in original_shape])
image = cv2.resize(image, new_size)
delta_w = new_shape[0] - new_size[0]
delta_h = new_shape[1] - new_size[1]
top, bottom = delta_h//2, delta_h-(delta_h//2)
left, right = delta_w//2, delta_w-(delta_w//2)
image = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT, value=padding_color)
return image
if __name__ == "__main__":
image = cv2.imread("/path/to/image")
image = resize_with_pad(image, (256, 256))
cv2.imshow("Padded image", image)
cv2.waitKey()
@TayJen
Copy link

TayJen commented Jan 27, 2023

Thanks man, really helped me today

@IdeaKing
Copy link
Author

Thanks man, really helped me today

No Problem!

@JeanPaulCE
Copy link

JeanPaulCE commented Feb 18, 2023

i like to suggest an optimization to work with any image size, the original code have a problem when the min dimension leng of the image after resize its bigger than the objective size in that dimension, only add this lines:

` Suggestion

if new_size[0] > new_shape[0] or new_size[1] > new_shape[1]:
    ratio = float(min(new_shape)) / min(original_shape)
    new_size = tuple([int(x * ratio) for x in original_shape])

`
that adjusts the ratio to resize the image in the range of objective size

the final function is this:

` Final Fnction

  def resize_with_pad(image: np.array, new_shape: Tuple[int, int], padding_color: Tuple[int] = (255, 255, 255)) -> np.array:
      original_shape = (image.shape[1], image.shape[0])
      ratio = float(max(new_shape))/max(original_shape)
      new_size = tuple([int(x*ratio) for x in original_shape])
  
      if new_size[0] > new_shape[0] or new_size[1] > new_shape[1]:
          ratio = float(min(new_shape)) / min(original_shape)
          new_size = tuple([int(x * ratio) for x in original_shape])
  
      image = cv2.resize(image, new_size)
      delta_w = new_shape[0] - new_size[0]
      delta_h = new_shape[1] - new_size[1]
      top, bottom = delta_h//2, delta_h-(delta_h//2)
      left, right = delta_w//2, delta_w-(delta_w//2)
  
      image = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT,None,value=padding_color)
      return image

`

@HessamLa
Copy link

In case of downsizing, delta_w or delta_h will become negative. The following is a fix:

    delta_w = new_shape[0] - new_size[0] if new_shape[0] > new_size[0] else 0
    delta_h = new_shape[1] - new_size[1] if new_shape[1] > new_size[1] else 0

@IdeaKing
Copy link
Author

i like to suggest an optimization to work with any image size, the original code have a problem when the min dimension leng of the image after resize its bigger than the objective size in that dimension, only add this lines:

` Suggestion

if new_size[0] > new_shape[0] or new_size[1] > new_shape[1]:
    ratio = float(min(new_shape)) / min(original_shape)
    new_size = tuple([int(x * ratio) for x in original_shape])

` that adjusts the ratio to resize the image in the range of objective size

the final function is this:

` Final Fnction

  def resize_with_pad(image: np.array, new_shape: Tuple[int, int], padding_color: Tuple[int] = (255, 255, 255)) -> np.array:
      original_shape = (image.shape[1], image.shape[0])
      ratio = float(max(new_shape))/max(original_shape)
      new_size = tuple([int(x*ratio) for x in original_shape])
  
      if new_size[0] > new_shape[0] or new_size[1] > new_shape[1]:
          ratio = float(min(new_shape)) / min(original_shape)
          new_size = tuple([int(x * ratio) for x in original_shape])
  
      image = cv2.resize(image, new_size)
      delta_w = new_shape[0] - new_size[0]
      delta_h = new_shape[1] - new_size[1]
      top, bottom = delta_h//2, delta_h-(delta_h//2)
      left, right = delta_w//2, delta_w-(delta_w//2)
  
      image = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT,None,value=padding_color)
      return image

`

Thanks! I will test it out and add it to the original.

@IdeaKing
Copy link
Author

In case of downsizing, delta_w or delta_h will become negative. The following is a fix:

    delta_w = new_shape[0] - new_size[0] if new_shape[0] > new_size[0] else 0
    delta_h = new_shape[1] - new_size[1] if new_shape[1] > new_size[1] else 0

Will take a look...

@barvin04
Copy link

Thank you @IdeaKing !

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