boxes_transform_rotate.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import numpy as np
  2. from .boxes_utils import assert_and_normalize_shape
  3. def rotate_boxes(boxes, angle, x_center=0, y_center=0, scale=1,
  4. degrees=True, return_rotated_boxes=False):
  5. """
  6. Args:
  7. boxes: (N, 4+K)
  8. angle: array-like whose shape is (), (1,), (N,), (1, 1) or (N, 1)
  9. x_center: array-like whose shape is (), (1,), (N,), (1, 1) or (N, 1)
  10. y_center: array-like whose shape is (), (1,), (N,), (1, 1) or (N, 1)
  11. scale: array-like whose shape is (), (1,), (N,), (1, 1) or (N, 1)
  12. scale factor in x and y dimension
  13. degrees: bool
  14. return_rotated_boxes: bool
  15. """
  16. boxes = np.asarray(boxes, np.float32)
  17. angle = np.asarray(angle, np.float32)
  18. x_center = np.asarray(x_center, np.float32)
  19. y_center = np.asarray(y_center, np.float32)
  20. scale = np.asarray(scale, np.float32)
  21. angle = assert_and_normalize_shape(angle, boxes.shape[0])
  22. x_center = assert_and_normalize_shape(x_center, boxes.shape[0])
  23. y_center = assert_and_normalize_shape(y_center, boxes.shape[0])
  24. scale = assert_and_normalize_shape(scale, boxes.shape[0])
  25. if degrees:
  26. angle = np.deg2rad(angle)
  27. cos_val = scale * np.cos(angle)
  28. sin_val = scale * np.sin(angle)
  29. x_shift = x_center - x_center * cos_val + y_center * sin_val
  30. y_shift = y_center - x_center * sin_val - y_center * cos_val
  31. x_mins, y_mins = boxes[:,0], boxes[:,1]
  32. x_maxs, y_maxs = boxes[:,2], boxes[:,3]
  33. x00 = x_mins * cos_val - y_mins * sin_val + x_shift
  34. x10 = x_maxs * cos_val - y_mins * sin_val + x_shift
  35. x11 = x_maxs * cos_val - y_maxs * sin_val + x_shift
  36. x01 = x_mins * cos_val - y_maxs * sin_val + x_shift
  37. y00 = x_mins * sin_val + y_mins * cos_val + y_shift
  38. y10 = x_maxs * sin_val + y_mins * cos_val + y_shift
  39. y11 = x_maxs * sin_val + y_maxs * cos_val + y_shift
  40. y01 = x_mins * sin_val + y_maxs * cos_val + y_shift
  41. rotated_boxes = np.stack([x00, y00, x10, y10, x11, y11, x01, y01], axis=-1)
  42. ret_x_mins = np.min(rotated_boxes[:,0::2], axis=1)
  43. ret_y_mins = np.min(rotated_boxes[:,1::2], axis=1)
  44. ret_x_maxs = np.max(rotated_boxes[:,0::2], axis=1)
  45. ret_y_maxs = np.max(rotated_boxes[:,1::2], axis=1)
  46. if boxes.ndim == 4:
  47. ret_boxes = np.stack([ret_x_mins, ret_y_mins, ret_x_maxs, ret_y_maxs], axis=-1)
  48. else:
  49. ret_boxes = boxes.copy()
  50. ret_boxes[:, :4] = np.stack([ret_x_mins, ret_y_mins, ret_x_maxs, ret_y_maxs], axis=-1)
  51. if not return_rotated_boxes:
  52. return ret_boxes
  53. else:
  54. return ret_boxes, rotated_boxes
  55. def rotate_boxes_wrt_centers(boxes, angle, scale=1, degrees=True,
  56. return_rotated_boxes=False):
  57. """
  58. Args:
  59. boxes: (N, 4+K)
  60. angle: array-like whose shape is (), (1,), (N,), (1, 1) or (N, 1)
  61. scale: array-like whose shape is (), (1,), (N,), (1, 1) or (N, 1)
  62. scale factor in x and y dimension
  63. degrees: bool
  64. return_rotated_boxes: bool
  65. """
  66. boxes = np.asarray(boxes, np.float32)
  67. angle = np.asarray(angle, np.float32)
  68. scale = np.asarray(scale, np.float32)
  69. angle = assert_and_normalize_shape(angle, boxes.shape[0])
  70. scale = assert_and_normalize_shape(scale, boxes.shape[0])
  71. if degrees:
  72. angle = np.deg2rad(angle)
  73. cos_val = scale * np.cos(angle)
  74. sin_val = scale * np.sin(angle)
  75. x_centers = boxes[:, 2] + boxes[:, 0]
  76. y_centers = boxes[:, 3] + boxes[:, 1]
  77. x_centers *= 0.5
  78. y_centers *= 0.5
  79. half_widths = boxes[:, 2] - boxes[:, 0]
  80. half_heights = boxes[:, 3] - boxes[:, 1]
  81. half_widths *= 0.5
  82. half_heights *= 0.5
  83. half_widths_cos = half_widths * cos_val
  84. half_widths_sin = half_widths * sin_val
  85. half_heights_cos = half_heights * cos_val
  86. half_heights_sin = half_heights * sin_val
  87. x00 = -half_widths_cos + half_heights_sin
  88. x10 = half_widths_cos + half_heights_sin
  89. x11 = half_widths_cos - half_heights_sin
  90. x01 = -half_widths_cos - half_heights_sin
  91. x00 += x_centers
  92. x10 += x_centers
  93. x11 += x_centers
  94. x01 += x_centers
  95. y00 = -half_widths_sin - half_heights_cos
  96. y10 = half_widths_sin - half_heights_cos
  97. y11 = half_widths_sin + half_heights_cos
  98. y01 = -half_widths_sin + half_heights_cos
  99. y00 += y_centers
  100. y10 += y_centers
  101. y11 += y_centers
  102. y01 += y_centers
  103. rotated_boxes = np.stack([x00, y00, x10, y10, x11, y11, x01, y01], axis=-1)
  104. ret_x_mins = np.min(rotated_boxes[:,0::2], axis=1)
  105. ret_y_mins = np.min(rotated_boxes[:,1::2], axis=1)
  106. ret_x_maxs = np.max(rotated_boxes[:,0::2], axis=1)
  107. ret_y_maxs = np.max(rotated_boxes[:,1::2], axis=1)
  108. if boxes.ndim == 4:
  109. ret_boxes = np.stack([ret_x_mins, ret_y_mins, ret_x_maxs, ret_y_maxs], axis=-1)
  110. else:
  111. ret_boxes = boxes.copy()
  112. ret_boxes[:, :4] = np.stack([ret_x_mins, ret_y_mins, ret_x_maxs, ret_y_maxs], axis=-1)
  113. if not return_rotated_boxes:
  114. return ret_boxes
  115. else:
  116. return ret_boxes, rotated_boxes