Skip to content

Commit ee58a4a

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

File tree

3 files changed

+269
-11
lines changed

3 files changed

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

tests/test_evaluation/test_functional/test_kitti_eval.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
# Copyright (c) OpenMMLab. All rights reserved.
22
import numpy as np
3-
import pytest
4-
import torch
53

64
from mmdet3d.evaluation import do_eval, eval_class, kitti_eval
75

86

97
def test_do_eval():
10-
if not torch.cuda.is_available():
11-
pytest.skip('test requires GPU and CUDA')
128
gt_name = np.array(
139
['Pedestrian', 'Cyclist', 'Car', 'Car', 'Car', 'DontCare', 'DontCare'])
1410
gt_truncated = np.array([0., 0., 0., -1., -1., -1., -1.])
@@ -128,8 +124,6 @@ def test_do_eval():
128124

129125

130126
def test_kitti_eval():
131-
if not torch.cuda.is_available():
132-
pytest.skip('test requires GPU and CUDA')
133127
gt_name = np.array(
134128
['Pedestrian', 'Cyclist', 'Car', 'Car', 'Car', 'DontCare', 'DontCare'])
135129
gt_truncated = np.array([0., 0., 0., -1., -1., -1., -1.])

0 commit comments

Comments
 (0)