You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

transform.py 4.9 kB

3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
  3. # File: transform.py
  4. import numpy as np
  5. from fvcore.transforms.transform import HFlipTransform, NoOpTransform, Transform
  6. from PIL import Image
  7. __all__ = ["ExtentTransform", "ResizeTransform"]
  8. class ExtentTransform(Transform):
  9. """
  10. Extracts a subregion from the source image and scales it to the output size.
  11. The fill color is used to map pixels from the source rect that fall outside
  12. the source image.
  13. See: https://pillow.readthedocs.io/en/latest/PIL.html#PIL.ImageTransform.ExtentTransform
  14. """
  15. def __init__(self, src_rect, output_size, interp=Image.LINEAR, fill=0):
  16. """
  17. Args:
  18. src_rect (x0, y0, x1, y1): src coordinates
  19. output_size (h, w): dst image size
  20. interp: PIL interpolation methods
  21. fill: Fill color used when src_rect extends outside image
  22. """
  23. super().__init__()
  24. self._set_attributes(locals())
  25. def apply_image(self, img, interp=None):
  26. h, w = self.output_size
  27. ret = Image.fromarray(img).transform(
  28. size=(w, h),
  29. method=Image.EXTENT,
  30. data=self.src_rect,
  31. resample=interp if interp else self.interp,
  32. fill=self.fill,
  33. )
  34. return np.asarray(ret)
  35. def apply_coords(self, coords):
  36. # Transform image center from source coordinates into output coordinates
  37. # and then map the new origin to the corner of the output image.
  38. h, w = self.output_size
  39. x0, y0, x1, y1 = self.src_rect
  40. new_coords = coords.astype(np.float32)
  41. new_coords[:, 0] -= 0.5 * (x0 + x1)
  42. new_coords[:, 1] -= 0.5 * (y0 + y1)
  43. new_coords[:, 0] *= w / (x1 - x0)
  44. new_coords[:, 1] *= h / (y1 - y0)
  45. new_coords[:, 0] += 0.5 * w
  46. new_coords[:, 1] += 0.5 * h
  47. return new_coords
  48. def apply_segmentation(self, segmentation):
  49. segmentation = self.apply_image(segmentation, interp=Image.NEAREST)
  50. return segmentation
  51. class ResizeTransform(Transform):
  52. """
  53. Resize the image to a target size.
  54. """
  55. def __init__(self, h, w, new_h, new_w, interp):
  56. """
  57. Args:
  58. h, w (int): original image size
  59. new_h, new_w (int): new image size
  60. interp: PIL interpolation methods
  61. """
  62. # TODO decide on PIL vs opencv
  63. super().__init__()
  64. self._set_attributes(locals())
  65. def apply_image(self, img, interp=None):
  66. assert img.shape[:2] == (self.h, self.w)
  67. pil_image = Image.fromarray(img)
  68. interp_method = interp if interp is not None else self.interp
  69. pil_image = pil_image.resize((self.new_w, self.new_h), interp_method)
  70. ret = np.asarray(pil_image)
  71. return ret
  72. def apply_coords(self, coords):
  73. coords[:, 0] = coords[:, 0] * (self.new_w * 1.0 / self.w)
  74. coords[:, 1] = coords[:, 1] * (self.new_h * 1.0 / self.h)
  75. return coords
  76. def apply_segmentation(self, segmentation):
  77. segmentation = self.apply_image(segmentation, interp=Image.NEAREST)
  78. return segmentation
  79. def HFlip_rotated_box(transform, rotated_boxes):
  80. """
  81. Apply the horizontal flip transform on rotated boxes.
  82. Args:
  83. rotated_boxes (ndarray): Nx5 floating point array of
  84. (x_center, y_center, width, height, angle_degrees) format
  85. in absolute coordinates.
  86. """
  87. # Transform x_center
  88. rotated_boxes[:, 0] = transform.width - rotated_boxes[:, 0]
  89. # Transform angle
  90. rotated_boxes[:, 4] = -rotated_boxes[:, 4]
  91. return rotated_boxes
  92. def Resize_rotated_box(transform, rotated_boxes):
  93. """
  94. Apply the resizing transform on rotated boxes. For details of how these (approximation)
  95. formulas are derived, please refer to :meth:`RotatedBoxes.scale`.
  96. Args:
  97. rotated_boxes (ndarray): Nx5 floating point array of
  98. (x_center, y_center, width, height, angle_degrees) format
  99. in absolute coordinates.
  100. """
  101. scale_factor_x = transform.new_w * 1.0 / transform.w
  102. scale_factor_y = transform.new_h * 1.0 / transform.h
  103. rotated_boxes[:, 0] *= scale_factor_x
  104. rotated_boxes[:, 1] *= scale_factor_y
  105. theta = rotated_boxes[:, 4] * np.pi / 180.0
  106. c = np.cos(theta)
  107. s = np.sin(theta)
  108. rotated_boxes[:, 2] *= np.sqrt(np.square(scale_factor_x * c) + np.square(scale_factor_y * s))
  109. rotated_boxes[:, 3] *= np.sqrt(np.square(scale_factor_x * s) + np.square(scale_factor_y * c))
  110. rotated_boxes[:, 4] = np.arctan2(scale_factor_x * s, scale_factor_y * c) * 180 / np.pi
  111. return rotated_boxes
  112. HFlipTransform.register_type("rotated_box", HFlip_rotated_box)
  113. NoOpTransform.register_type("rotated_box", lambda t, x: x)
  114. ResizeTransform.register_type("rotated_box", Resize_rotated_box)

No Description