Complex-YOLOv4-Pytorch
Complex-YOLOv4-Pytorch copied to clipboard
intersection of rotate bounding box error
https://github.com/maudzung/Complex-YOLOv4-Pytorch/blob/564e8e35ad81f5a9f1a24ca4ceaf10908a100bfd/src/utils/cal_intersection_rotated_boxes.py#L78
I think there should be limitations to the range of intersection points.
In the following case, intersection values are calculated as 400.0 even though the boxes do not intersect.
box1 = torch.tensor([100, 100, 40, 10, np.pi / 2], dtype=torch.float).cuda()
box2 = torch.tensor([200, 100, 40, 20, 0], dtype=torch.float).cuda()
Shapely- box1_area: 400.00, box2_area: 800.00, inter: 0.00, iou: 0.0000
intersection from intersection_area(): 400.0

@JJangD you can try this
`import torch import cv2 import numpy as np from shapely.geometry import Polygon
class Line: # ax + by + c = 0 def init(self, p1, p2): """
Args:
p1: (x, y)
p2: (x, y)
"""
self.a = p2[1] - p1[1]
self.b = p1[0] - p2[0]
self.c = p2[0] * p1[1] - p2[1] * p1[0] # cross
self.device = p1.device
def cal_values(self, pts):
return self.a * pts[:, 0] + self.b * pts[:, 1] + self.c
def find_intersection(self, other):
# See e.g. https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Using_homogeneous_coordinates
if not isinstance(other, Line):
return NotImplemented
w = self.a * other.b - self.b * other.a
return torch.tensor([(self.b * other.c - self.c * other.b) / w, (self.c * other.a - self.a * other.c) / w],
device=self.device)
def intersection_area(rect1, rect2): """Calculate the inter
Args:
rect1: vertices of the rectangles (4, 2)
rect2: vertices of the rectangles (4, 2)
Returns:
"""
# Use the vertices of the first rectangle as, starting vertices of the intersection polygon.
intersection = rect1
# Loop over the edges of the second rectangle
roll_rect2 = torch.roll(rect2, -1, dims=0)
roll_rect2second = torch.roll(roll_rect2, -1, dims=0)
for p, q in zip(roll_rect2, roll_rect2second):
if len(intersection) <= 2:
break # No intersection
line = Line(p, q)
# Any point p with line(p) <= 0 is on the "inside" (or on the boundary),
# any point p with line(p) > 0 is on the "outside".
# Loop over the edges of the intersection polygon,
# and determine which part is inside and which is outside.
new_intersection = []
line_values = line.cal_values(intersection)
roll_intersection = torch.roll(intersection, -1, dims=0)
roll_line_values = torch.roll(line_values, -1, dims=0)
for s, t, s_value, t_value in zip(intersection, roll_intersection, line_values, roll_line_values):
if s_value <= 0:
new_intersection.append(s)
if s_value * t_value < 0:
# Points are on opposite sides.
# Add the intersection of the lines to new_intersection.
intersection_point = line.find_intersection(Line(s, t))
new_intersection.append(intersection_point)
if len(new_intersection) > 0:
intersection = torch.stack(new_intersection)
else:
for i in range(4):
canditorch = torch.tensor([0, 0], device = p.device)
new_intersection.append(canditorch)
intersection = torch.stack(new_intersection)
# Calculate area
if len(intersection) <= 2:
return 0.
return PolyArea2D(intersection)
def PolyArea2D(pts): roll_pts = torch.roll(pts, -1, dims=0) area = (pts[:, 0] * roll_pts[:, 1] - pts[:, 1] * roll_pts[:, 0]).sum().abs() * 0.5 return area
if name == "main":
def cvt_box_2_polygon(box):
"""
:param array: an array of shape [num_conners, 2]
:return: a shapely.geometry.Polygon object
"""
# use .buffer(0) to fix a line polygon
box.reshape(-1, 2)
# more infor: https://stackoverflow.com/questions/13062334/polygon-intersection-error-in-shapely-shapely-geos-topologicalerror-the-opera
return Polygon(box).buffer(0)
def get_corners_torch(x, y, w, l, yaw):
device = x.device
bev_corners = torch.zeros((4, 2), dtype=torch.float, device=device)
cos_yaw = torch.cos(yaw)
sin_yaw = torch.sin(yaw)
# front left
bev_corners[0, 0] = x - w / 2 * cos_yaw - l / 2 * sin_yaw
bev_corners[0, 1] = y - w / 2 * sin_yaw + l / 2 * cos_yaw
# rear left
bev_corners[1, 0] = x - w / 2 * cos_yaw + l / 2 * sin_yaw
bev_corners[1, 1] = y - w / 2 * sin_yaw - l / 2 * cos_yaw
# rear right
bev_corners[2, 0] = x + w / 2 * cos_yaw + l / 2 * sin_yaw
bev_corners[2, 1] = y + w / 2 * sin_yaw - l / 2 * cos_yaw
# front right
bev_corners[3, 0] = x + w / 2 * cos_yaw - l / 2 * sin_yaw
bev_corners[3, 1] = y + w / 2 * sin_yaw + l / 2 * cos_yaw
return bev_corners
# Show convex in an image
img_size = 300
img = np.zeros((img_size, img_size, 3))
img = cv2.resize(img, (img_size, img_size))
box1 = torch.tensor([100, 100, 40, 5, np.pi / 2], dtype=torch.float).cuda()
box2 = torch.tensor([200, 200, 50, 20, 0], dtype=torch.float).cuda()
box1_conners = get_corners_torch(box1[0], box1[1], box1[2], box1[3], box1[4])
box1_polygon = cvt_box_2_polygon(box1_conners)
box1_area = box1_polygon.area
box2_conners = get_corners_torch(box2[0], box2[1], box2[2], box2[3], box2[4])
box2_polygon = cvt_box_2_polygon(box2_conners)
box2_area = box2_polygon.area
intersection = box2_polygon.intersection(box1_polygon).area
union = box1_area + box2_area - intersection
iou = intersection / (union + 1e-16)
print('Shapely- box1_area: {:.2f}, box2_area: {:.2f}, inter: {:.2f}, iou: {:.4f}'.format(box1_area, box2_area,
intersection, iou))
print('intersection from intersection_area(): {}'.format(intersection_area(box1_conners, box2_conners)))
img = cv2.polylines(img, [box1_conners.cpu().numpy().astype(np.int)], True, (255, 0, 0), 2)
img = cv2.polylines(img, [box2_conners.cpu().numpy().astype(np.int)], True, (0, 255, 0), 2)
while True:
cv2.imshow('img', img)
if cv2.waitKey(0) & 0xff == 27:
break`
Shapely- box1_area: 400.00, box2_area: 800.00, inter: 0.00, iou: 0.0000 intersection from intersection_area(): 0.0
@wangx1996 Can you describe what the issue was and what the solution was? Is your insertion of the second roll operation necessary?