boxbase.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import math
  2. def is_in(box1, box2) -> bool:
  3. """box1是否完全在box2里面."""
  4. x0_1, y0_1, x1_1, y1_1 = box1
  5. x0_2, y0_2, x1_2, y1_2 = box2
  6. return (
  7. x0_1 >= x0_2 # box1的左边界不在box2的左边外
  8. and y0_1 >= y0_2 # box1的上边界不在box2的上边外
  9. and x1_1 <= x1_2 # box1的右边界不在box2的右边外
  10. and y1_1 <= y1_2
  11. ) # box1的下边界不在box2的下边外
  12. def bbox_relative_pos(bbox1, bbox2):
  13. """判断两个矩形框的相对位置关系.
  14. Args:
  15. bbox1: 一个四元组,表示第一个矩形框的左上角和右下角的坐标,格式为(x1, y1, x1b, y1b)
  16. bbox2: 一个四元组,表示第二个矩形框的左上角和右下角的坐标,格式为(x2, y2, x2b, y2b)
  17. Returns:
  18. 一个四元组,表示矩形框1相对于矩形框2的位置关系,格式为(left, right, bottom, top)
  19. 其中,left表示矩形框1是否在矩形框2的左侧,right表示矩形框1是否在矩形框2的右侧,
  20. bottom表示矩形框1是否在矩形框2的下方,top表示矩形框1是否在矩形框2的上方
  21. """
  22. x1, y1, x1b, y1b = bbox1
  23. x2, y2, x2b, y2b = bbox2
  24. left = x2b < x1
  25. right = x1b < x2
  26. bottom = y2b < y1
  27. top = y1b < y2
  28. return left, right, bottom, top
  29. def bbox_distance(bbox1, bbox2):
  30. """计算两个矩形框的距离。
  31. Args:
  32. bbox1 (tuple): 第一个矩形框的坐标,格式为 (x1, y1, x2, y2),其中 (x1, y1) 为左上角坐标,(x2, y2) 为右下角坐标。
  33. bbox2 (tuple): 第二个矩形框的坐标,格式为 (x1, y1, x2, y2),其中 (x1, y1) 为左上角坐标,(x2, y2) 为右下角坐标。
  34. Returns:
  35. float: 矩形框之间的距离。
  36. """
  37. def dist(point1, point2):
  38. return math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2)
  39. x1, y1, x1b, y1b = bbox1
  40. x2, y2, x2b, y2b = bbox2
  41. left, right, bottom, top = bbox_relative_pos(bbox1, bbox2)
  42. if top and left:
  43. return dist((x1, y1b), (x2b, y2))
  44. elif left and bottom:
  45. return dist((x1, y1), (x2b, y2b))
  46. elif bottom and right:
  47. return dist((x1b, y1), (x2, y2b))
  48. elif right and top:
  49. return dist((x1b, y1b), (x2, y2))
  50. elif left:
  51. return x1 - x2b
  52. elif right:
  53. return x2 - x1b
  54. elif bottom:
  55. return y1 - y2b
  56. elif top:
  57. return y2 - y1b
  58. return 0.0
  59. def get_minbox_if_overlap_by_ratio(bbox1, bbox2, ratio):
  60. """通过calculate_overlap_area_2_minbox_area_ratio计算两个bbox重叠的面积占最小面积的box的比例
  61. 如果比例大于ratio,则返回小的那个bbox, 否则返回None."""
  62. x1_min, y1_min, x1_max, y1_max = bbox1
  63. x2_min, y2_min, x2_max, y2_max = bbox2
  64. area1 = (x1_max - x1_min) * (y1_max - y1_min)
  65. area2 = (x2_max - x2_min) * (y2_max - y2_min)
  66. overlap_ratio = calculate_overlap_area_2_minbox_area_ratio(bbox1, bbox2)
  67. if overlap_ratio > ratio:
  68. if area1 <= area2:
  69. return bbox1
  70. else:
  71. return bbox2
  72. else:
  73. return None
  74. def calculate_overlap_area_2_minbox_area_ratio(bbox1, bbox2):
  75. """计算box1和box2的重叠面积占最小面积的box的比例."""
  76. # Determine the coordinates of the intersection rectangle
  77. x_left = max(bbox1[0], bbox2[0])
  78. y_top = max(bbox1[1], bbox2[1])
  79. x_right = min(bbox1[2], bbox2[2])
  80. y_bottom = min(bbox1[3], bbox2[3])
  81. if x_right < x_left or y_bottom < y_top:
  82. return 0.0
  83. # The area of overlap area
  84. intersection_area = (x_right - x_left) * (y_bottom - y_top)
  85. min_box_area = min([(bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1]),
  86. (bbox2[3] - bbox2[1]) * (bbox2[2] - bbox2[0])])
  87. if min_box_area == 0:
  88. return 0
  89. else:
  90. return intersection_area / min_box_area
  91. def calculate_iou(bbox1, bbox2):
  92. """计算两个边界框的交并比(IOU)。
  93. Args:
  94. bbox1 (list[float]): 第一个边界框的坐标,格式为 [x1, y1, x2, y2],其中 (x1, y1) 为左上角坐标,(x2, y2) 为右下角坐标。
  95. bbox2 (list[float]): 第二个边界框的坐标,格式与 `bbox1` 相同。
  96. Returns:
  97. float: 两个边界框的交并比(IOU),取值范围为 [0, 1]。
  98. """
  99. # Determine the coordinates of the intersection rectangle
  100. x_left = max(bbox1[0], bbox2[0])
  101. y_top = max(bbox1[1], bbox2[1])
  102. x_right = min(bbox1[2], bbox2[2])
  103. y_bottom = min(bbox1[3], bbox2[3])
  104. if x_right < x_left or y_bottom < y_top:
  105. return 0.0
  106. # The area of overlap area
  107. intersection_area = (x_right - x_left) * (y_bottom - y_top)
  108. # The area of both rectangles
  109. bbox1_area = (bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1])
  110. bbox2_area = (bbox2[2] - bbox2[0]) * (bbox2[3] - bbox2[1])
  111. if any([bbox1_area == 0, bbox2_area == 0]):
  112. return 0
  113. # Compute the intersection over union by taking the intersection area
  114. # and dividing it by the sum of both areas minus the intersection area
  115. iou = intersection_area / float(bbox1_area + bbox2_area - intersection_area)
  116. return iou
  117. def _is_in(box1, box2) -> bool:
  118. """box1是否完全在box2里面."""
  119. x0_1, y0_1, x1_1, y1_1 = box1
  120. x0_2, y0_2, x1_2, y1_2 = box2
  121. return (x0_1 >= x0_2 and # box1的左边界不在box2的左边外
  122. y0_1 >= y0_2 and # box1的上边界不在box2的上边外
  123. x1_1 <= x1_2 and # box1的右边界不在box2的右边外
  124. y1_1 <= y1_2) # box1的下边界不在box2的下边外