ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
IoUImpl.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #pragma once
9 
10 #include <math.h>
11 
12 #include "Macro.h"
14 
15 namespace cloudViewer {
16 namespace ml {
17 namespace contrib {
18 
19 constexpr int NMS_BLOCK_SIZE = sizeof(uint64_t) * 8;
20 constexpr float EPS = static_cast<float>(1e-8);
21 
22 struct Point {
24  CLOUDVIEWER_HOST_DEVICE Point(float x, float y) : x_(x), y_(y) {}
25  CLOUDVIEWER_HOST_DEVICE void set(float x, float y) {
26  x_ = x;
27  y_ = y;
28  }
30  return Point(x_ + b.x_, y_ + b.y_);
31  }
33  return Point(x_ - b.x_, y_ - b.y_);
34  }
35  float x_ = 0.0f;
36  float y_ = 0.0f;
37 };
38 
39 CLOUDVIEWER_HOST_DEVICE inline float Cross(const Point &a, const Point &b) {
40  return a.x_ * b.y_ - a.y_ * b.x_;
41 }
42 
43 CLOUDVIEWER_HOST_DEVICE inline float Cross(const Point &p1,
44  const Point &p2,
45  const Point &p0) {
46  return (p1.x_ - p0.x_) * (p2.y_ - p0.y_) -
47  (p2.x_ - p0.x_) * (p1.y_ - p0.y_);
48 }
49 
51  const Point &p2,
52  const Point &q1,
53  const Point &q2) {
54  int ret = fmin(p1.x_, p2.x_) <= fmax(q1.x_, q2.x_) &&
55  fmin(q1.x_, q2.x_) <= fmax(p1.x_, p2.x_) &&
56  fmin(p1.y_, p2.y_) <= fmax(q1.y_, q2.y_) &&
57  fmin(q1.y_, q2.y_) <= fmax(p1.y_, p2.y_);
58  return ret;
59 }
60 
61 CLOUDVIEWER_HOST_DEVICE inline int CheckInBox2D(const float *box,
62  const Point &p) {
63  // box (5): [x1, y1, x2, y2, angle].
64  const float MARGIN = static_cast<float>(1e-5);
65 
66  float center_x = (box[0] + box[2]) / 2;
67  float center_y = (box[1] + box[3]) / 2;
68  // Rotate the point in the opposite direction of box.
69  float angle_cos = cos(-box[4]), angle_sin = sin(-box[4]);
70  float rot_x = (p.x_ - center_x) * angle_cos +
71  (p.y_ - center_y) * angle_sin + center_x;
72  float rot_y = -(p.x_ - center_x) * angle_sin +
73  (p.y_ - center_y) * angle_cos + center_y;
74  return (rot_x > box[0] - MARGIN && rot_x < box[2] + MARGIN &&
75  rot_y > box[1] - MARGIN && rot_y < box[3] + MARGIN);
76 }
77 
79  const Point &p0,
80  const Point &q1,
81  const Point &q0,
82  Point &ans) {
83  // Fast exclusion.
84  if (CheckRectCross(p0, p1, q0, q1) == 0) return 0;
85 
86  // Check Cross standing
87  float s1 = Cross(q0, p1, p0);
88  float s2 = Cross(p1, q1, p0);
89  float s3 = Cross(p0, q1, q0);
90  float s4 = Cross(q1, p1, q0);
91 
92  if (!(s1 * s2 > 0 && s3 * s4 > 0)) return 0;
93 
94  // Calculate Intersection of two lines.
95  float s5 = Cross(q1, p1, p0);
96  if (fabs(s5 - s1) > EPS) {
97  ans.x_ = (s5 * q0.x_ - s1 * q1.x_) / (s5 - s1);
98  ans.y_ = (s5 * q0.y_ - s1 * q1.y_) / (s5 - s1);
99 
100  } else {
101  float a0 = p0.y_ - p1.y_, b0 = p1.x_ - p0.x_,
102  c0 = p0.x_ * p1.y_ - p1.x_ * p0.y_;
103  float a1 = q0.y_ - q1.y_, b1 = q1.x_ - q0.x_,
104  c1 = q0.x_ * q1.y_ - q1.x_ * q0.y_;
105  float D = a0 * b1 - a1 * b0;
106 
107  ans.x_ = (b0 * c1 - b1 * c0) / D;
108  ans.y_ = (a1 * c0 - a0 * c1) / D;
109  }
110 
111  return 1;
112 }
113 
115  const float angle_cos,
116  const float angle_sin,
117  Point &p) {
118  float new_x = (p.x_ - center.x_) * angle_cos +
119  (p.y_ - center.y_) * angle_sin + center.x_;
120  float new_y = -(p.x_ - center.x_) * angle_sin +
121  (p.y_ - center.y_) * angle_cos + center.y_;
122  p.set(new_x, new_y);
123 }
124 
126  const Point &b,
127  const Point &center) {
128  return atan2(a.y_ - center.y_, a.x_ - center.x_) >
129  atan2(b.y_ - center.y_, b.x_ - center.x_);
130 }
131 
132 CLOUDVIEWER_HOST_DEVICE inline float BoxOverlap(const float *box_a,
133  const float *box_b) {
134  // box_a (5) [x1, y1, x2, y2, angle].
135  // box_b (5) [x1, y1, x2, y2, angle].
136  float a_x1 = box_a[0], a_y1 = box_a[1], a_x2 = box_a[2], a_y2 = box_a[3],
137  a_angle = box_a[4];
138  float b_x1 = box_b[0], b_y1 = box_b[1], b_x2 = box_b[2], b_y2 = box_b[3],
139  b_angle = box_b[4];
140 
141  Point center_a((a_x1 + a_x2) / 2, (a_y1 + a_y2) / 2);
142  Point center_b((b_x1 + b_x2) / 2, (b_y1 + b_y2) / 2);
143 
144  Point box_a_corners[5];
145  box_a_corners[0].set(a_x1, a_y1);
146  box_a_corners[1].set(a_x2, a_y1);
147  box_a_corners[2].set(a_x2, a_y2);
148  box_a_corners[3].set(a_x1, a_y2);
149 
150  Point box_b_corners[5];
151  box_b_corners[0].set(b_x1, b_y1);
152  box_b_corners[1].set(b_x2, b_y1);
153  box_b_corners[2].set(b_x2, b_y2);
154  box_b_corners[3].set(b_x1, b_y2);
155 
156  // Get oriented corners.
157  float a_angle_cos = cos(a_angle), a_angle_sin = sin(a_angle);
158  float b_angle_cos = cos(b_angle), b_angle_sin = sin(b_angle);
159 
160  for (int k = 0; k < 4; k++) {
161  RotateAroundCenter(center_a, a_angle_cos, a_angle_sin,
162  box_a_corners[k]);
163  RotateAroundCenter(center_b, b_angle_cos, b_angle_sin,
164  box_b_corners[k]);
165  }
166 
167  box_a_corners[4] = box_a_corners[0];
168  box_b_corners[4] = box_b_corners[0];
169 
170  // Get Intersection of lines.
171  Point cross_points[16];
172  Point poly_center;
173  int cnt = 0, flag = 0;
174 
175  poly_center.set(0, 0);
176  for (int i = 0; i < 4; i++) {
177  for (int j = 0; j < 4; j++) {
178  flag = Intersection(box_a_corners[i + 1], box_a_corners[i],
179  box_b_corners[j + 1], box_b_corners[j],
180  cross_points[cnt]);
181  if (flag) {
182  poly_center = poly_center + cross_points[cnt];
183  cnt++;
184  }
185  }
186  }
187 
188  // Check corners.
189  for (int k = 0; k < 4; k++) {
190  if (CheckInBox2D(box_a, box_b_corners[k])) {
191  poly_center = poly_center + box_b_corners[k];
192  cross_points[cnt] = box_b_corners[k];
193  cnt++;
194  }
195  if (CheckInBox2D(box_b, box_a_corners[k])) {
196  poly_center = poly_center + box_a_corners[k];
197  cross_points[cnt] = box_a_corners[k];
198  cnt++;
199  }
200  }
201 
202  CLOUDVIEWER_ASSERT(cnt != 0 && "Invalid value: cnt==0.");
203 
204  poly_center.x_ /= cnt;
205  poly_center.y_ /= cnt;
206 
207  // Sort the points of polygon.
208  Point temp;
209  for (int j = 0; j < cnt - 1; j++) {
210  for (int i = 0; i < cnt - j - 1; i++) {
211  if (PointCmp(cross_points[i], cross_points[i + 1], poly_center)) {
212  temp = cross_points[i];
213  cross_points[i] = cross_points[i + 1];
214  cross_points[i + 1] = temp;
215  }
216  }
217  }
218 
219  // Get the overlap areas.
220  float area = 0;
221  for (int k = 0; k < cnt - 1; k++) {
222  area += Cross(cross_points[k] - cross_points[0],
223  cross_points[k + 1] - cross_points[0]);
224  }
225 
226  return static_cast<float>(fabs(area)) / 2.0f;
227 }
228 
231  const float *box_a,
232  const float *box_b,
233  bool intersection_only = false) {
234  // params: box_a (5) [x1, y1, x2, y2, angle].
235  // params: box_b (5) [x1, y1, x2, y2, angle].
236  float sa = (box_a[2] - box_a[0]) * (box_a[3] - box_a[1]);
237  float sb = (box_b[2] - box_b[0]) * (box_b[3] - box_b[1]);
238  float s_overlap = BoxOverlap(box_a, box_b);
239  if (intersection_only) {
240  return s_overlap;
241  } else {
242  return s_overlap / fmaxf(sa + sb - s_overlap, EPS);
243  }
244 }
245 
248  const float *box_a,
249  const float *box_b,
250  bool intersection_only = false) {
251  float box_a_new[5];
252  box_a_new[0] = box_a[0] - box_a[2] / 2;
253  box_a_new[1] = box_a[1] - box_a[3] / 2;
254  box_a_new[2] = box_a[0] + box_a[2] / 2;
255  box_a_new[3] = box_a[1] + box_a[3] / 2;
256  box_a_new[4] = box_a[4];
257 
258  float box_b_new[5];
259  box_b_new[0] = box_b[0] - box_b[2] / 2;
260  box_b_new[1] = box_b[1] - box_b[3] / 2;
261  box_b_new[2] = box_b[0] + box_b[2] / 2;
262  box_b_new[3] = box_b[1] + box_b[3] / 2;
263  box_b_new[4] = box_b[4];
264  return IoUBev2DWithMinAndMax(box_a_new, box_b_new, intersection_only);
265 }
266 
269  const float *box_a, const float *box_b) {
270  float box_a_2d[5];
271  box_a_2d[0] = box_a[0];
272  box_a_2d[1] = box_a[2];
273  box_a_2d[2] = box_a[3];
274  box_a_2d[3] = box_a[5];
275  box_a_2d[4] = box_a[6];
276 
277  float box_b_2d[5];
278  box_b_2d[0] = box_b[0];
279  box_b_2d[1] = box_b[2];
280  box_b_2d[2] = box_b[3];
281  box_b_2d[3] = box_b[5];
282  box_b_2d[4] = box_b[6];
283  float intersection_2d = IoUBev2DWithCenterAndSize(box_a_2d, box_b_2d, true);
284 
285  float y_a_min = box_a[1] - box_a[4];
286  float y_a_max = box_a[1];
287  float y_b_min = box_b[1] - box_b[4];
288  float y_b_max = box_b[1];
289  float iw = (y_a_max < y_b_max ? y_a_max : y_b_max) -
290  (y_a_min > y_b_min ? y_a_min : y_b_min);
291  float iou_3d = 0;
292  if (iw > 0) {
293  float intersection_3d = intersection_2d * iw;
294  float volume_a = box_a[3] * box_a[4] * box_a[5];
295  float volume_b = box_b[3] * box_b[4] * box_b[5];
296  float union_3d = volume_a + volume_b - intersection_3d;
297  iou_3d = intersection_3d / union_3d;
298  }
299  return iou_3d;
300 }
301 
302 } // namespace contrib
303 } // namespace ml
304 } // namespace cloudViewer
Common CUDA utilities.
#define CLOUDVIEWER_HOST_DEVICE
Definition: CUDAUtils.h:44
#define CLOUDVIEWER_ASSERT(...)
Definition: Macro.h:51
float fmaxf(float a, float b)
Definition: cutil_math.h:43
__host__ __device__ float2 fabs(float2 v)
Definition: cutil_math.h:1254
CLOUDVIEWER_HOST_DEVICE int PointCmp(const Point &a, const Point &b, const Point &center)
Definition: IoUImpl.h:125
constexpr float EPS
Definition: IoUImpl.h:20
CLOUDVIEWER_HOST_DEVICE float IoUBev2DWithMinAndMax(const float *box_a, const float *box_b, bool intersection_only=false)
(x_min, z_min, x_max, z_max, y_rotate)
Definition: IoUImpl.h:230
CLOUDVIEWER_HOST_DEVICE int CheckInBox2D(const float *box, const Point &p)
Definition: IoUImpl.h:61
CLOUDVIEWER_HOST_DEVICE int CheckRectCross(const Point &p1, const Point &p2, const Point &q1, const Point &q2)
Definition: IoUImpl.h:50
CLOUDVIEWER_HOST_DEVICE int Intersection(const Point &p1, const Point &p0, const Point &q1, const Point &q0, Point &ans)
Definition: IoUImpl.h:78
CLOUDVIEWER_HOST_DEVICE float IoUBev2DWithCenterAndSize(const float *box_a, const float *box_b, bool intersection_only=false)
(x_center, z_center, x_size, z_size, y_rotate)
Definition: IoUImpl.h:247
CLOUDVIEWER_HOST_DEVICE void RotateAroundCenter(const Point &center, const float angle_cos, const float angle_sin, Point &p)
Definition: IoUImpl.h:114
CLOUDVIEWER_HOST_DEVICE float IoU3DWithCenterAndSize(const float *box_a, const float *box_b)
(x_center, y_max, z_center, x_size, y_size, z_size, y_rotate)
Definition: IoUImpl.h:268
CLOUDVIEWER_HOST_DEVICE float Cross(const Point &a, const Point &b)
Definition: IoUImpl.h:39
constexpr int NMS_BLOCK_SIZE
Definition: IoUImpl.h:19
CLOUDVIEWER_HOST_DEVICE float BoxOverlap(const float *box_a, const float *box_b)
Definition: IoUImpl.h:132
Generic file read and write utility for python interface.
CLOUDVIEWER_HOST_DEVICE Point()
Definition: IoUImpl.h:23
CLOUDVIEWER_HOST_DEVICE Point operator-(const Point &b) const
Definition: IoUImpl.h:32
CLOUDVIEWER_HOST_DEVICE Point operator+(const Point &b) const
Definition: IoUImpl.h:29
CLOUDVIEWER_HOST_DEVICE void set(float x, float y)
Definition: IoUImpl.h:25
CLOUDVIEWER_HOST_DEVICE Point(float x, float y)
Definition: IoUImpl.h:24