Skip to content

Commit 8e50136

Browse files
committed
[Add] Add rotate iou cpu evaluation on kitti dateset
1 parent fe25f7a commit 8e50136

File tree

2 files changed

+267
-5
lines changed

2 files changed

+267
-5
lines changed

mmdet3d/evaluation/functional/kitti_utils/eval.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import numba
66
import numpy as np
7+
import torch
78

89

910
@numba.jit
@@ -115,8 +116,12 @@ def image_box_overlap(boxes, query_boxes, criterion=-1):
115116

116117

117118
def bev_box_overlap(boxes, qboxes, criterion=-1):
118-
from .rotate_iou import rotate_iou_gpu_eval
119-
riou = rotate_iou_gpu_eval(boxes, qboxes, criterion)
119+
if torch.cuda.is_available():
120+
from .rotate_iou import rotate_iou_gpu_eval
121+
riou = rotate_iou_gpu_eval(boxes, qboxes, criterion)
122+
else:
123+
from .rotate_iou_cpu import rotate_iou_cpu_eval
124+
riou = rotate_iou_cpu_eval(boxes, qboxes, criterion)
120125
return riou
121126

122127

@@ -153,9 +158,14 @@ def d3_box_overlap_kernel(boxes, qboxes, rinc, criterion=-1):
153158

154159

155160
def d3_box_overlap(boxes, qboxes, criterion=-1):
156-
from .rotate_iou import rotate_iou_gpu_eval
157-
rinc = rotate_iou_gpu_eval(boxes[:, [0, 2, 3, 5, 6]],
158-
qboxes[:, [0, 2, 3, 5, 6]], 2)
161+
if torch.cuda.is_available():
162+
from .rotate_iou import rotate_iou_gpu_eval
163+
rinc = rotate_iou_gpu_eval(boxes[:, [0, 2, 3, 5, 6]],
164+
qboxes[:, [0, 2, 3, 5, 6]], 2)
165+
else:
166+
from .rotate_iou_cpu import rotate_iou_cpu_eval
167+
rinc = rotate_iou_cpu_eval(boxes[:, [0, 2, 3, 5, 6]],
168+
qboxes[:, [0, 2, 3, 5, 6]], 2)
159169
d3_box_overlap_kernel(boxes, qboxes, rinc, criterion)
160170
return rinc
161171

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
# Copyright (c) OpenMMLab. All rights reserved.
2+
#####################
3+
# Based on https://github.com/hongzhenwang/RRPN-revise
4+
# Licensed under The MIT License
5+
# Author: yanyan, scrin@foxmail.com
6+
#####################
7+
import math
8+
import numpy as np
9+
10+
11+
def div_up(m, n):
12+
return m // n + (m % n > 0)
13+
14+
def trangle_area(a, b, c):
15+
return ((a[0] - c[0]) * (b[1] - c[1]) - (a[1] - c[1]) *
16+
(b[0] - c[0])) / 2.0
17+
18+
19+
def area(int_pts, num_of_inter):
20+
area_val = 0.0
21+
for i in range(num_of_inter - 2):
22+
area_val += abs(
23+
trangle_area(int_pts[:2], int_pts[2 * i + 2:2 * i + 4],
24+
int_pts[2 * i + 4:2 * i + 6]))
25+
return area_val
26+
27+
28+
def sort_vertex_in_convex_polygon(int_pts, num_of_inter):
29+
if num_of_inter > 0:
30+
center = np.zeros((2, ), dtype=np.float32)
31+
center[:] = 0.0
32+
for i in range(num_of_inter):
33+
center[0] += int_pts[2 * i]
34+
center[1] += int_pts[2 * i + 1]
35+
center[0] /= num_of_inter
36+
center[1] /= num_of_inter
37+
v = np.zeros((2, ), dtype=np.float32)
38+
vs = np.zeros((16, ), dtype=np.float32)
39+
for i in range(num_of_inter):
40+
v[0] = int_pts[2 * i] - center[0]
41+
v[1] = int_pts[2 * i + 1] - center[1]
42+
d = math.sqrt(v[0] * v[0] + v[1] * v[1])
43+
v[0] = v[0] / d
44+
v[1] = v[1] / d
45+
if v[1] < 0:
46+
v[0] = -2 - v[0]
47+
vs[i] = v[0]
48+
j = 0
49+
temp = 0
50+
for i in range(1, num_of_inter):
51+
if vs[i - 1] > vs[i]:
52+
temp = vs[i]
53+
tx = int_pts[2 * i]
54+
ty = int_pts[2 * i + 1]
55+
j = i
56+
while j > 0 and vs[j - 1] > temp:
57+
vs[j] = vs[j - 1]
58+
int_pts[j * 2] = int_pts[j * 2 - 2]
59+
int_pts[j * 2 + 1] = int_pts[j * 2 - 1]
60+
j -= 1
61+
62+
vs[j] = temp
63+
int_pts[j * 2] = tx
64+
int_pts[j * 2 + 1] = ty
65+
66+
67+
def line_segment_intersection(pts1, pts2, i, j, temp_pts):
68+
A = np.zeros((2, ), dtype=np.float32)
69+
B = np.zeros((2, ), dtype=np.float32)
70+
C = np.zeros((2, ), dtype=np.float32)
71+
D = np.zeros((2, ), dtype=np.float32)
72+
73+
A[0] = pts1[2 * i]
74+
A[1] = pts1[2 * i + 1]
75+
76+
B[0] = pts1[2 * ((i + 1) % 4)]
77+
B[1] = pts1[2 * ((i + 1) % 4) + 1]
78+
79+
C[0] = pts2[2 * j]
80+
C[1] = pts2[2 * j + 1]
81+
82+
D[0] = pts2[2 * ((j + 1) % 4)]
83+
D[1] = pts2[2 * ((j + 1) % 4) + 1]
84+
BA0 = B[0] - A[0]
85+
BA1 = B[1] - A[1]
86+
DA0 = D[0] - A[0]
87+
CA0 = C[0] - A[0]
88+
DA1 = D[1] - A[1]
89+
CA1 = C[1] - A[1]
90+
acd = DA1 * CA0 > CA1 * DA0
91+
bcd = (D[1] - B[1]) * (C[0] - B[0]) > (C[1] - B[1]) * (D[0] - B[0])
92+
if acd != bcd:
93+
abc = CA1 * BA0 > BA1 * CA0
94+
abd = DA1 * BA0 > BA1 * DA0
95+
if abc != abd:
96+
DC0 = D[0] - C[0]
97+
DC1 = D[1] - C[1]
98+
ABBA = A[0] * B[1] - B[0] * A[1]
99+
CDDC = C[0] * D[1] - D[0] * C[1]
100+
DH = BA1 * DC0 - BA0 * DC1
101+
Dx = ABBA * DC0 - BA0 * CDDC
102+
Dy = ABBA * DC1 - BA1 * CDDC
103+
temp_pts[0] = Dx / DH
104+
temp_pts[1] = Dy / DH
105+
return True
106+
return False
107+
108+
109+
def line_segment_intersection_v1(pts1, pts2, i, j, temp_pts):
110+
a = np.zeros((2, ), dtype=np.float32)
111+
b = np.zeros((2, ), dtype=np.float32)
112+
c = np.zeros((2, ), dtype=np.float32)
113+
d = np.zeros((2, ), dtype=np.float32)
114+
115+
a[0] = pts1[2 * i]
116+
a[1] = pts1[2 * i + 1]
117+
118+
b[0] = pts1[2 * ((i + 1) % 4)]
119+
b[1] = pts1[2 * ((i + 1) % 4) + 1]
120+
121+
c[0] = pts2[2 * j]
122+
c[1] = pts2[2 * j + 1]
123+
124+
d[0] = pts2[2 * ((j + 1) % 4)]
125+
d[1] = pts2[2 * ((j + 1) % 4) + 1]
126+
127+
area_abc = trangle_area(a, b, c)
128+
area_abd = trangle_area(a, b, d)
129+
130+
if area_abc * area_abd >= 0:
131+
return False
132+
133+
area_cda = trangle_area(c, d, a)
134+
area_cdb = area_cda + area_abc - area_abd
135+
136+
if area_cda * area_cdb >= 0:
137+
return False
138+
t = area_cda / (area_abd - area_abc)
139+
140+
dx = t * (b[0] - a[0])
141+
dy = t * (b[1] - a[1])
142+
temp_pts[0] = a[0] + dx
143+
temp_pts[1] = a[1] + dy
144+
return True
145+
146+
147+
def point_in_quadrilateral(pt_x, pt_y, corners):
148+
ab0 = corners[2] - corners[0]
149+
ab1 = corners[3] - corners[1]
150+
151+
ad0 = corners[6] - corners[0]
152+
ad1 = corners[7] - corners[1]
153+
154+
ap0 = pt_x - corners[0]
155+
ap1 = pt_y - corners[1]
156+
157+
abab = ab0 * ab0 + ab1 * ab1
158+
abap = ab0 * ap0 + ab1 * ap1
159+
adad = ad0 * ad0 + ad1 * ad1
160+
adap = ad0 * ap0 + ad1 * ap1
161+
162+
return abab >= abap and abap >= 0 and adad >= adap and adap >= 0
163+
164+
165+
def quadrilateral_intersection(pts1, pts2, int_pts):
166+
num_of_inter = 0
167+
for i in range(4):
168+
if point_in_quadrilateral(pts1[2 * i], pts1[2 * i + 1], pts2):
169+
int_pts[num_of_inter * 2] = pts1[2 * i]
170+
int_pts[num_of_inter * 2 + 1] = pts1[2 * i + 1]
171+
num_of_inter += 1
172+
if point_in_quadrilateral(pts2[2 * i], pts2[2 * i + 1], pts1):
173+
int_pts[num_of_inter * 2] = pts2[2 * i]
174+
int_pts[num_of_inter * 2 + 1] = pts2[2 * i + 1]
175+
num_of_inter += 1
176+
temp_pts = np.zeros((2, ), dtype=np.float32)
177+
for i in range(4):
178+
for j in range(4):
179+
has_pts = line_segment_intersection(pts1, pts2, i, j, temp_pts)
180+
if has_pts:
181+
int_pts[num_of_inter * 2] = temp_pts[0]
182+
int_pts[num_of_inter * 2 + 1] = temp_pts[1]
183+
num_of_inter += 1
184+
185+
return num_of_inter
186+
187+
188+
def rbbox_to_corners(corners, rbbox):
189+
# generate clockwise corners and rotate it clockwise
190+
angle = rbbox[4]
191+
a_cos = math.cos(angle)
192+
a_sin = math.sin(angle)
193+
center_x = rbbox[0]
194+
center_y = rbbox[1]
195+
x_d = rbbox[2]
196+
y_d = rbbox[3]
197+
corners_x = np.zeros((4, ), dtype=np.float32)
198+
corners_y = np.zeros((4, ), dtype=np.float32)
199+
corners_x[0] = -x_d / 2
200+
corners_x[1] = -x_d / 2
201+
corners_x[2] = x_d / 2
202+
corners_x[3] = x_d / 2
203+
corners_y[0] = -y_d / 2
204+
corners_y[1] = y_d / 2
205+
corners_y[2] = y_d / 2
206+
corners_y[3] = -y_d / 2
207+
for i in range(4):
208+
corners[2 *
209+
i] = a_cos * corners_x[i] + a_sin * corners_y[i] + center_x
210+
corners[2 * i
211+
+ 1] = -a_sin * corners_x[i] + a_cos * corners_y[i] + center_y
212+
213+
214+
def inter(rbbox1, rbbox2):
215+
corners1 = np.zeros((8, ), dtype=np.float32)
216+
corners2 = np.zeros((8, ), dtype=np.float32)
217+
intersection_corners = np.zeros((16, ), dtype=np.float32)
218+
219+
rbbox_to_corners(corners1, rbbox1)
220+
rbbox_to_corners(corners2, rbbox2)
221+
222+
num_intersection = quadrilateral_intersection(corners1, corners2,
223+
intersection_corners)
224+
sort_vertex_in_convex_polygon(intersection_corners, num_intersection)
225+
# print(intersection_corners.reshape([-1, 2])[:num_intersection])
226+
227+
return area(intersection_corners, num_intersection)
228+
229+
230+
def devRotateIoUEval(rbox1, rbox2, criterion=-1):
231+
area1 = rbox1[2] * rbox1[3]
232+
area2 = rbox2[2] * rbox2[3]
233+
area_inter = inter(rbox1, rbox2)
234+
if criterion == -1:
235+
return area_inter / (area1 + area2 - area_inter)
236+
elif criterion == 0:
237+
return area_inter / area1
238+
elif criterion == 1:
239+
return area_inter / area2
240+
else:
241+
return area_inter
242+
243+
244+
def rotate_iou_cpu_eval(dev_boxes, dev_query_boxes, criterion=-1):
245+
num_boxes = dev_boxes.shape[0]
246+
num_qboxes = dev_query_boxes.shape[0]
247+
dev_iou = np.zeros((num_boxes, num_qboxes))
248+
for box_i in range(num_boxes):
249+
for qbox_i in range(num_qboxes):
250+
dev_iou[box_i, qbox_i] = devRotateIoUEval(dev_query_boxes[qbox_i], dev_boxes[box_i], criterion)
251+
252+
return dev_iou

0 commit comments

Comments
 (0)