crop_or_pad.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import numbers
  2. import khandy
  3. import numpy as np
  4. def crop_or_pad(image, x_min, y_min, x_max, y_max, border_value=0):
  5. """
  6. See Also:
  7. translate_image
  8. References:
  9. tf.image.resize_image_with_crop_or_pad
  10. """
  11. assert khandy.is_numpy_image(image)
  12. assert isinstance(x_min, numbers.Integral) and isinstance(y_min, numbers.Integral)
  13. assert isinstance(x_max, numbers.Integral) and isinstance(y_max, numbers.Integral)
  14. assert (x_min <= x_max) and (y_min <= y_max)
  15. src_height, src_width = image.shape[:2]
  16. dst_height, dst_width = y_max - y_min + 1, x_max - x_min + 1
  17. channels = 1 if image.ndim == 2 else image.shape[2]
  18. if image.ndim == 2:
  19. dst_image_shape = (dst_height, dst_width)
  20. else:
  21. dst_image_shape = (dst_height, dst_width, channels)
  22. if isinstance(border_value, numbers.Real):
  23. dst_image = np.full(dst_image_shape, border_value, dtype=image.dtype)
  24. elif isinstance(border_value, tuple):
  25. assert len(border_value) == channels, \
  26. 'Expected the num of elements in tuple equals the channels' \
  27. 'of input image. Found {} vs {}'.format(
  28. len(border_value), channels)
  29. if channels == 1:
  30. dst_image = np.full(dst_image_shape, border_value[0], dtype=image.dtype)
  31. else:
  32. border_value = np.asarray(border_value, dtype=image.dtype)
  33. dst_image = np.empty(dst_image_shape, dtype=image.dtype)
  34. dst_image[:] = border_value
  35. else:
  36. raise ValueError(
  37. 'Invalid type {} for `border_value`.'.format(type(border_value)))
  38. src_x_begin = max(x_min, 0)
  39. src_x_end = min(x_max + 1, src_width)
  40. dst_x_begin = src_x_begin - x_min
  41. dst_x_end = src_x_end - x_min
  42. src_y_begin = max(y_min, 0)
  43. src_y_end = min(y_max + 1, src_height)
  44. dst_y_begin = src_y_begin - y_min
  45. dst_y_end = src_y_end - y_min
  46. if (src_x_begin >= src_x_end) or (src_y_begin >= src_y_end):
  47. return dst_image
  48. dst_image[dst_y_begin: dst_y_end, dst_x_begin: dst_x_end, ...] = \
  49. image[src_y_begin: src_y_end, src_x_begin: src_x_end, ...]
  50. return dst_image
  51. def crop_or_pad_coords(boxes, image_width, image_height):
  52. """
  53. References:
  54. `mmcv.impad`
  55. `pad` in https://github.com/kpzhang93/MTCNN_face_detection_alignment
  56. `MtcnnDetector.pad` in https://github.com/AITTSMD/MTCNN-Tensorflow
  57. """
  58. x_mins = boxes[:, 0]
  59. y_mins = boxes[:, 1]
  60. x_maxs = boxes[:, 2]
  61. y_maxs = boxes[:, 3]
  62. dst_widths = x_maxs - x_mins + 1
  63. dst_heights = y_maxs - y_mins + 1
  64. src_x_begin = np.maximum(x_mins, 0)
  65. src_x_end = np.minimum(x_maxs + 1, image_width)
  66. dst_x_begin = src_x_begin - x_mins
  67. dst_x_end = src_x_end - x_mins
  68. src_y_begin = np.maximum(y_mins, 0)
  69. src_y_end = np.minimum(y_maxs + 1, image_height)
  70. dst_y_begin = src_y_begin - y_mins
  71. dst_y_end = src_y_end - y_mins
  72. coords = np.stack([dst_y_begin, dst_y_end, dst_x_begin, dst_x_end,
  73. src_y_begin, src_y_end, src_x_begin, src_x_end,
  74. dst_heights, dst_widths], axis=0)
  75. return coords
  76. def center_crop(image, dst_width, dst_height, strict=True):
  77. """
  78. strict:
  79. when True, raise error if src size is less than dst size.
  80. when False, remain unchanged if src size is less than dst size, otherwise center crop.
  81. """
  82. assert khandy.is_numpy_image(image)
  83. assert isinstance(dst_width, numbers.Integral) and isinstance(dst_height, numbers.Integral)
  84. src_height, src_width = image.shape[:2]
  85. if strict:
  86. assert (src_height >= dst_height) and (src_width >= dst_width)
  87. crop_top = max((src_height - dst_height) // 2, 0)
  88. crop_left = max((src_width - dst_width) // 2, 0)
  89. cropped = image[crop_top: dst_height + crop_top,
  90. crop_left: dst_width + crop_left, ...]
  91. return cropped
  92. def center_pad(image, dst_width, dst_height, strict=True):
  93. """
  94. strict:
  95. when True, raise error if src size is greater than dst size.
  96. when False, remain unchanged if src size is greater than dst size, otherwise center pad.
  97. """
  98. assert khandy.is_numpy_image(image)
  99. assert isinstance(dst_width, numbers.Integral) and isinstance(dst_height, numbers.Integral)
  100. src_height, src_width = image.shape[:2]
  101. if strict:
  102. assert (src_height <= dst_height) and (src_width <= dst_width)
  103. padding_x = max(dst_width - src_width, 0)
  104. padding_y = max(dst_height - src_height, 0)
  105. padding_top = padding_y // 2
  106. padding_left = padding_x // 2
  107. if image.ndim == 2:
  108. padding = ((padding_top, padding_y - padding_top),
  109. (padding_left, padding_x - padding_left))
  110. else:
  111. padding = ((padding_top, padding_y - padding_top),
  112. (padding_left, padding_x - padding_left), (0, 0))
  113. return np.pad(image, padding, 'constant')