insecta / khandy /image /resize.py
admin
sync
67a9b5d
import warnings
import cv2
import khandy
import numpy as np
interp_codes = {
'nearest': cv2.INTER_NEAREST,
'bilinear': cv2.INTER_LINEAR,
'bicubic': cv2.INTER_CUBIC,
'area': cv2.INTER_AREA,
'lanczos': cv2.INTER_LANCZOS4
}
def scale_image(image, x_scale, y_scale, interpolation='bilinear'):
"""Scale image.
Reference:
mmcv.imrescale
"""
assert khandy.is_numpy_image(image)
src_height, src_width = image.shape[:2]
dst_width = int(round(x_scale * src_width))
dst_height = int(round(y_scale * src_height))
resized_image = cv2.resize(image, (dst_width, dst_height),
interpolation=interp_codes[interpolation])
return resized_image
def resize_image(image, dst_width, dst_height, return_scale=False, interpolation='bilinear'):
"""Resize image to a given size.
Args:
image (ndarray): The input image.
dst_width (int): Target width.
dst_height (int): Target height.
return_scale (bool): Whether to return `x_scale` and `y_scale`.
interpolation (str): Interpolation method, accepted values are
"nearest", "bilinear", "bicubic", "area", "lanczos".
Returns:
tuple or ndarray: (`resized_image`, `x_scale`, `y_scale`) or `resized_image`.
Reference:
mmcv.imresize
"""
assert khandy.is_numpy_image(image)
resized_image = cv2.resize(image, (dst_width, dst_height),
interpolation=interp_codes[interpolation])
if not return_scale:
return resized_image
else:
src_height, src_width = image.shape[:2]
x_scale = dst_width / src_width
y_scale = dst_height / src_height
return resized_image, x_scale, y_scale
def resize_image_short(image, dst_size, return_scale=False, interpolation='bilinear'):
"""Resize an image so that the length of shorter side is dst_size while
preserving the original aspect ratio.
References:
`resize_min` in `https://github.com/pjreddie/darknet/blob/master/src/image.c`
"""
assert khandy.is_numpy_image(image)
src_height, src_width = image.shape[:2]
scale = max(dst_size / src_width, dst_size / src_height)
dst_width = int(round(scale * src_width))
dst_height = int(round(scale * src_height))
resized_image = cv2.resize(image, (dst_width, dst_height),
interpolation=interp_codes[interpolation])
if not return_scale:
return resized_image
else:
return resized_image, scale
def resize_image_long(image, dst_size, return_scale=False, interpolation='bilinear'):
"""Resize an image so that the length of longer side is dst_size while
preserving the original aspect ratio.
References:
`resize_max` in `https://github.com/pjreddie/darknet/blob/master/src/image.c`
"""
assert khandy.is_numpy_image(image)
src_height, src_width = image.shape[:2]
scale = min(dst_size / src_width, dst_size / src_height)
dst_width = int(round(scale * src_width))
dst_height = int(round(scale * src_height))
resized_image = cv2.resize(image, (dst_width, dst_height),
interpolation=interp_codes[interpolation])
if not return_scale:
return resized_image
else:
return resized_image, scale
def resize_image_to_range(image, min_length, max_length, return_scale=False, interpolation='bilinear'):
"""Resizes an image so its dimensions are within the provided value.
Rescale the shortest side of the image up to `min_length` pixels
while keeping the largest side below `max_length` pixels without
changing the aspect ratio. Often used in object detection (e.g. RCNN and SSH.)
The output size can be described by two cases:
1. If the image can be rescaled so its shortest side is equal to the
`min_length` without the other side exceeding `max_length`, then do so.
2. Otherwise, resize so the longest side is equal to `max_length`.
Returns:
resized_image: resized image so that
min(dst_height, dst_width) == min_length or
max(dst_height, dst_width) == max_length.
References:
`resize_to_range` in `models-master/research/object_detection/core/preprocessor.py`
`prep_im_for_blob` in `py-faster-rcnn-master/lib/utils/blob.py`
mmcv.imrescale
"""
assert khandy.is_numpy_image(image)
assert min_length < max_length
src_height, src_width = image.shape[:2]
min_side_length = min(src_width, src_height)
max_side_length = max(src_width, src_height)
scale = min_length / min_side_length
if round(scale * max_side_length) > max_length:
scale = max_length / max_side_length
dst_width = int(round(scale * src_width))
dst_height = int(round(scale * src_height))
resized_image = cv2.resize(image, (dst_width, dst_height),
interpolation=interp_codes[interpolation])
if not return_scale:
return resized_image
else:
return resized_image, scale
def letterbox_image(image, dst_width, dst_height, border_value=0,
return_scale=False, interpolation='bilinear'):
"""Resize an image preserving the original aspect ratio using padding.
References:
`letterbox_image` in `https://github.com/pjreddie/darknet/blob/master/src/image.c`
"""
assert khandy.is_numpy_image(image)
src_height, src_width = image.shape[:2]
scale = min(dst_width / src_width, dst_height / src_height)
resize_w = int(round(scale * src_width))
resize_h = int(round(scale * src_height))
resized_image = cv2.resize(image, (resize_w, resize_h),
interpolation=interp_codes[interpolation])
pad_top = (dst_height - resize_h) // 2
pad_bottom = (dst_height - resize_h) - pad_top
pad_left = (dst_width - resize_w) // 2
pad_right = (dst_width - resize_w) - pad_left
padded_image = cv2.copyMakeBorder(resized_image, pad_top, pad_bottom, pad_left, pad_right,
cv2.BORDER_CONSTANT, value=border_value)
if not return_scale:
return padded_image
else:
return padded_image, scale, pad_left, pad_top
def letterbox_resize_image(image, dst_width, dst_height, border_value=0,
return_scale=False, interpolation='bilinear'):
warnings.warn('letterbox_resize_image will be deprecated, use letterbox_image instead!')
return letterbox_image(image, dst_width, dst_height, border_value,
return_scale, interpolation)