test_horizontal_boxes.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import random
  2. from math import sqrt
  3. from unittest import TestCase
  4. import cv2
  5. import numpy as np
  6. import torch
  7. from mmengine.testing import assert_allclose
  8. from mmdet.structures.bbox import HorizontalBoxes
  9. from mmdet.structures.mask import BitmapMasks, PolygonMasks
  10. class TestHorizontalBoxes(TestCase):
  11. def test_init(self):
  12. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  13. th_boxes_cxcywh = torch.Tensor([15, 15, 10, 10]).reshape(1, 1, 4)
  14. boxes = HorizontalBoxes(th_boxes)
  15. assert_allclose(boxes.tensor, th_boxes)
  16. boxes = HorizontalBoxes(th_boxes, in_mode='xyxy')
  17. assert_allclose(boxes.tensor, th_boxes)
  18. boxes = HorizontalBoxes(th_boxes_cxcywh, in_mode='cxcywh')
  19. assert_allclose(boxes.tensor, th_boxes)
  20. with self.assertRaises(ValueError):
  21. boxes = HorizontalBoxes(th_boxes, in_mode='invalid')
  22. def test_cxcywh(self):
  23. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  24. th_boxes_cxcywh = torch.Tensor([15, 15, 10, 10]).reshape(1, 1, 4)
  25. boxes = HorizontalBoxes(th_boxes)
  26. assert_allclose(
  27. HorizontalBoxes.xyxy_to_cxcywh(th_boxes), th_boxes_cxcywh)
  28. assert_allclose(th_boxes,
  29. HorizontalBoxes.cxcywh_to_xyxy(th_boxes_cxcywh))
  30. assert_allclose(boxes.cxcywh, th_boxes_cxcywh)
  31. def test_propoerty(self):
  32. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  33. boxes = HorizontalBoxes(th_boxes)
  34. # Centers
  35. centers = torch.Tensor([15, 15]).reshape(1, 1, 2)
  36. assert_allclose(boxes.centers, centers)
  37. # Areas
  38. areas = torch.Tensor([100]).reshape(1, 1)
  39. assert_allclose(boxes.areas, areas)
  40. # widths
  41. widths = torch.Tensor([10]).reshape(1, 1)
  42. assert_allclose(boxes.widths, widths)
  43. # heights
  44. heights = torch.Tensor([10]).reshape(1, 1)
  45. assert_allclose(boxes.heights, heights)
  46. def test_flip(self):
  47. img_shape = [50, 85]
  48. # horizontal flip
  49. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  50. flipped_boxes_th = torch.Tensor([65, 10, 75, 20]).reshape(1, 1, 4)
  51. boxes = HorizontalBoxes(th_boxes)
  52. boxes.flip_(img_shape, direction='horizontal')
  53. assert_allclose(boxes.tensor, flipped_boxes_th)
  54. # vertical flip
  55. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  56. flipped_boxes_th = torch.Tensor([10, 30, 20, 40]).reshape(1, 1, 4)
  57. boxes = HorizontalBoxes(th_boxes)
  58. boxes.flip_(img_shape, direction='vertical')
  59. assert_allclose(boxes.tensor, flipped_boxes_th)
  60. # diagonal flip
  61. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  62. flipped_boxes_th = torch.Tensor([65, 30, 75, 40]).reshape(1, 1, 4)
  63. boxes = HorizontalBoxes(th_boxes)
  64. boxes.flip_(img_shape, direction='diagonal')
  65. assert_allclose(boxes.tensor, flipped_boxes_th)
  66. def test_translate(self):
  67. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  68. boxes = HorizontalBoxes(th_boxes)
  69. boxes.translate_([23, 46])
  70. translated_boxes_th = torch.Tensor([33, 56, 43, 66]).reshape(1, 1, 4)
  71. assert_allclose(boxes.tensor, translated_boxes_th)
  72. def test_clip(self):
  73. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  74. img_shape = [13, 14]
  75. boxes = HorizontalBoxes(th_boxes)
  76. boxes.clip_(img_shape)
  77. cliped_boxes_th = torch.Tensor([10, 10, 14, 13]).reshape(1, 1, 4)
  78. assert_allclose(boxes.tensor, cliped_boxes_th)
  79. def test_rotate(self):
  80. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  81. center = (15, 15)
  82. angle = -45
  83. boxes = HorizontalBoxes(th_boxes)
  84. boxes.rotate_(center, angle)
  85. rotated_boxes_th = torch.Tensor([
  86. 15 - 5 * sqrt(2), 15 - 5 * sqrt(2), 15 + 5 * sqrt(2),
  87. 15 + 5 * sqrt(2)
  88. ]).reshape(1, 1, 4)
  89. assert_allclose(boxes.tensor, rotated_boxes_th)
  90. def test_project(self):
  91. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  92. boxes1 = HorizontalBoxes(th_boxes)
  93. boxes2 = boxes1.clone()
  94. matrix = np.zeros((3, 3), dtype=np.float32)
  95. center = [random.random() * 80, random.random() * 80]
  96. angle = random.random() * 180
  97. matrix[:2, :3] = cv2.getRotationMatrix2D(center, angle, 1)
  98. x_translate = random.random() * 40
  99. y_translate = random.random() * 40
  100. matrix[0, 2] = matrix[0, 2] + x_translate
  101. matrix[1, 2] = matrix[1, 2] + y_translate
  102. scale_factor = random.random() * 2
  103. matrix[2, 2] = 1 / scale_factor
  104. boxes1.project_(matrix)
  105. boxes2.rotate_(center, -angle)
  106. boxes2.translate_([x_translate, y_translate])
  107. boxes2.rescale_([scale_factor, scale_factor])
  108. assert_allclose(boxes1.tensor, boxes2.tensor)
  109. # test empty boxes
  110. empty_boxes = HorizontalBoxes(torch.zeros((0, 4)))
  111. empty_boxes.project_(matrix)
  112. def test_rescale(self):
  113. scale_factor = [0.4, 0.8]
  114. # rescale
  115. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  116. boxes = HorizontalBoxes(th_boxes)
  117. boxes.rescale_(scale_factor)
  118. rescaled_boxes_th = torch.Tensor([4, 8, 8, 16]).reshape(1, 1, 4)
  119. assert_allclose(boxes.tensor, rescaled_boxes_th)
  120. def test_resize(self):
  121. scale_factor = [0.4, 0.8]
  122. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 1, 4)
  123. boxes = HorizontalBoxes(th_boxes)
  124. boxes.resize_(scale_factor)
  125. resized_boxes_th = torch.Tensor([13, 11, 17, 19]).reshape(1, 1, 4)
  126. assert_allclose(boxes.tensor, resized_boxes_th)
  127. def test_is_inside(self):
  128. th_boxes = torch.Tensor([[10, 10, 20, 20], [-5, -5, 15, 15],
  129. [45, 45, 55, 55]]).reshape(1, 3, 4)
  130. img_shape = [30, 30]
  131. boxes = HorizontalBoxes(th_boxes)
  132. index = boxes.is_inside(img_shape)
  133. index_th = torch.BoolTensor([True, True, False]).reshape(1, 3)
  134. assert_allclose(index, index_th)
  135. def test_find_inside_points(self):
  136. th_boxes = torch.Tensor([10, 10, 20, 20]).reshape(1, 4)
  137. boxes = HorizontalBoxes(th_boxes)
  138. points = torch.Tensor([[0, 0], [0, 15], [15, 0], [15, 15]])
  139. index = boxes.find_inside_points(points)
  140. index_th = torch.BoolTensor([False, False, False, True]).reshape(4, 1)
  141. assert_allclose(index, index_th)
  142. # is_aligned
  143. boxes = boxes.expand(4, 4)
  144. index = boxes.find_inside_points(points, is_aligned=True)
  145. index_th = torch.BoolTensor([False, False, False, True])
  146. assert_allclose(index, index_th)
  147. def test_from_instance_masks(self):
  148. bitmap_masks = BitmapMasks.random()
  149. boxes = HorizontalBoxes.from_instance_masks(bitmap_masks)
  150. self.assertIsInstance(boxes, HorizontalBoxes)
  151. self.assertEqual(len(boxes), len(bitmap_masks))
  152. polygon_masks = PolygonMasks.random()
  153. boxes = HorizontalBoxes.from_instance_masks(polygon_masks)
  154. self.assertIsInstance(boxes, HorizontalBoxes)
  155. self.assertEqual(len(boxes), len(bitmap_masks))
  156. # zero length masks
  157. bitmap_masks = BitmapMasks.random(num_masks=0)
  158. boxes = HorizontalBoxes.from_instance_masks(bitmap_masks)
  159. self.assertIsInstance(boxes, HorizontalBoxes)
  160. self.assertEqual(len(boxes), 0)
  161. polygon_masks = PolygonMasks.random(num_masks=0)
  162. boxes = HorizontalBoxes.from_instance_masks(polygon_masks)
  163. self.assertIsInstance(boxes, HorizontalBoxes)
  164. self.assertEqual(len(boxes), 0)