resize.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import warnings
  2. import cv2
  3. import khandy
  4. import numpy as np
  5. interp_codes = {
  6. 'nearest': cv2.INTER_NEAREST,
  7. 'bilinear': cv2.INTER_LINEAR,
  8. 'bicubic': cv2.INTER_CUBIC,
  9. 'area': cv2.INTER_AREA,
  10. 'lanczos': cv2.INTER_LANCZOS4
  11. }
  12. def scale_image(image, x_scale, y_scale, interpolation='bilinear'):
  13. """Scale image.
  14. Reference:
  15. mmcv.imrescale
  16. """
  17. assert khandy.is_numpy_image(image)
  18. src_height, src_width = image.shape[:2]
  19. dst_width = int(round(x_scale * src_width))
  20. dst_height = int(round(y_scale * src_height))
  21. resized_image = cv2.resize(image, (dst_width, dst_height),
  22. interpolation=interp_codes[interpolation])
  23. return resized_image
  24. def resize_image(image, dst_width, dst_height, return_scale=False, interpolation='bilinear'):
  25. """Resize image to a given size.
  26. Args:
  27. image (ndarray): The input image.
  28. dst_width (int): Target width.
  29. dst_height (int): Target height.
  30. return_scale (bool): Whether to return `x_scale` and `y_scale`.
  31. interpolation (str): Interpolation method, accepted values are
  32. "nearest", "bilinear", "bicubic", "area", "lanczos".
  33. Returns:
  34. tuple or ndarray: (`resized_image`, `x_scale`, `y_scale`) or `resized_image`.
  35. Reference:
  36. mmcv.imresize
  37. """
  38. assert khandy.is_numpy_image(image)
  39. resized_image = cv2.resize(image, (dst_width, dst_height),
  40. interpolation=interp_codes[interpolation])
  41. if not return_scale:
  42. return resized_image
  43. else:
  44. src_height, src_width = image.shape[:2]
  45. x_scale = dst_width / src_width
  46. y_scale = dst_height / src_height
  47. return resized_image, x_scale, y_scale
  48. def resize_image_short(image, dst_size, return_scale=False, interpolation='bilinear'):
  49. """Resize an image so that the length of shorter side is dst_size while
  50. preserving the original aspect ratio.
  51. References:
  52. `resize_min` in `https://github.com/pjreddie/darknet/blob/master/src/image.c`
  53. """
  54. assert khandy.is_numpy_image(image)
  55. src_height, src_width = image.shape[:2]
  56. scale = max(dst_size / src_width, dst_size / src_height)
  57. dst_width = int(round(scale * src_width))
  58. dst_height = int(round(scale * src_height))
  59. resized_image = cv2.resize(image, (dst_width, dst_height),
  60. interpolation=interp_codes[interpolation])
  61. if not return_scale:
  62. return resized_image
  63. else:
  64. return resized_image, scale
  65. def resize_image_long(image, dst_size, return_scale=False, interpolation='bilinear'):
  66. """Resize an image so that the length of longer side is dst_size while
  67. preserving the original aspect ratio.
  68. References:
  69. `resize_max` in `https://github.com/pjreddie/darknet/blob/master/src/image.c`
  70. """
  71. assert khandy.is_numpy_image(image)
  72. src_height, src_width = image.shape[:2]
  73. scale = min(dst_size / src_width, dst_size / src_height)
  74. dst_width = int(round(scale * src_width))
  75. dst_height = int(round(scale * src_height))
  76. resized_image = cv2.resize(image, (dst_width, dst_height),
  77. interpolation=interp_codes[interpolation])
  78. if not return_scale:
  79. return resized_image
  80. else:
  81. return resized_image, scale
  82. def resize_image_to_range(image, min_length, max_length, return_scale=False, interpolation='bilinear'):
  83. """Resizes an image so its dimensions are within the provided value.
  84. Rescale the shortest side of the image up to `min_length` pixels
  85. while keeping the largest side below `max_length` pixels without
  86. changing the aspect ratio. Often used in object detection (e.g. RCNN and SSH.)
  87. The output size can be described by two cases:
  88. 1. If the image can be rescaled so its shortest side is equal to the
  89. `min_length` without the other side exceeding `max_length`, then do so.
  90. 2. Otherwise, resize so the longest side is equal to `max_length`.
  91. Returns:
  92. resized_image: resized image so that
  93. min(dst_height, dst_width) == min_length or
  94. max(dst_height, dst_width) == max_length.
  95. References:
  96. `resize_to_range` in `models-master/research/object_detection/core/preprocessor.py`
  97. `prep_im_for_blob` in `py-faster-rcnn-master/lib/utils/blob.py`
  98. mmcv.imrescale
  99. """
  100. assert khandy.is_numpy_image(image)
  101. assert min_length < max_length
  102. src_height, src_width = image.shape[:2]
  103. min_side_length = min(src_width, src_height)
  104. max_side_length = max(src_width, src_height)
  105. scale = min_length / min_side_length
  106. if round(scale * max_side_length) > max_length:
  107. scale = max_length / max_side_length
  108. dst_width = int(round(scale * src_width))
  109. dst_height = int(round(scale * src_height))
  110. resized_image = cv2.resize(image, (dst_width, dst_height),
  111. interpolation=interp_codes[interpolation])
  112. if not return_scale:
  113. return resized_image
  114. else:
  115. return resized_image, scale
  116. def letterbox_image(image, dst_width, dst_height, border_value=0,
  117. return_scale=False, interpolation='bilinear'):
  118. """Resize an image preserving the original aspect ratio using padding.
  119. References:
  120. `letterbox_image` in `https://github.com/pjreddie/darknet/blob/master/src/image.c`
  121. """
  122. assert khandy.is_numpy_image(image)
  123. src_height, src_width = image.shape[:2]
  124. scale = min(dst_width / src_width, dst_height / src_height)
  125. resize_w = int(round(scale * src_width))
  126. resize_h = int(round(scale * src_height))
  127. resized_image = cv2.resize(image, (resize_w, resize_h),
  128. interpolation=interp_codes[interpolation])
  129. pad_top = (dst_height - resize_h) // 2
  130. pad_bottom = (dst_height - resize_h) - pad_top
  131. pad_left = (dst_width - resize_w) // 2
  132. pad_right = (dst_width - resize_w) - pad_left
  133. padded_image = cv2.copyMakeBorder(resized_image, pad_top, pad_bottom, pad_left, pad_right,
  134. cv2.BORDER_CONSTANT, value=border_value)
  135. if not return_scale:
  136. return padded_image
  137. else:
  138. return padded_image, scale, pad_left, pad_top
  139. def letterbox_resize_image(image, dst_width, dst_height, border_value=0,
  140. return_scale=False, interpolation='bilinear'):
  141. warnings.warn('letterbox_resize_image will be deprecated, use letterbox_image instead!')
  142. return letterbox_image(image, dst_width, dst_height, border_value,
  143. return_scale, interpolation)