Apollo  6.0
Open source self driving car software
twod_threed_util.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2018 The Apollo Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *****************************************************************************/
16 #pragma once
17 
18 #include <algorithm>
19 #include <limits>
20 #include <utility>
21 
22 #include "cyber/common/log.h"
26 
27 namespace apollo {
28 namespace perception {
29 namespace camera {
30 
31 /*auxiliary data structure*/
32 template <typename T>
33 struct LineSegment2D {
34  T pt_start[2] = {0}; // left
35  T pt_end[2] = {0}; // right
36 
37  LineSegment2D(const T &x_start, const T &y_start, const T &x_end,
38  const T &y_end) {
39  pt_start[0] = x_start;
40  pt_start[1] = y_start;
41  pt_end[0] = x_end;
42  pt_end[1] = y_end;
43  }
45  this->pt_start[0] = ls.pt_start[0];
46  this->pt_start[1] = ls.pt_start[1];
47  this->pt_end[0] = ls.pt_end[0];
48  this->pt_end[1] = ls.pt_end[1];
49  }
50  void operator=(const LineSegment2D &ls) {
51  this->pt_start[0] = ls.pt_start[0];
52  this->pt_start[1] = ls.pt_start[1];
53  this->pt_end[0] = ls.pt_end[0];
54  this->pt_end[1] = ls.pt_end[1];
55  }
56 };
57 /*end of auxiliary data structure*/
58 
59 /*angle util*/
60 template <typename T>
61 T CalAngleDiff(const T a1, const T a2) {
62  T diff1 = a1 - a2;
63  diff1 = diff1 < 0 ? -diff1 : diff1;
64  T diff2 = a1 - a2 + common::Constant<T>::PI() * 2;
65  diff2 = diff2 < 0 ? -diff2 : diff2;
66  T diff3 = a1 - a2 - common::Constant<T>::PI() * 2;
67  diff3 = diff3 < 0 ? -diff3 : diff3;
68  return std::min<T>(std::min<T>(diff1, diff2), diff3);
69 }
70 
71 template <typename T>
72 inline T GetSharpAngle(const T &a, const T &b) {
73  /*a and b are in [-pi, pi)*/
74  const T pi = common::Constant<T>::PI();
75  T angle = std::abs(a - b);
76  if (angle > pi) {
77  angle -= pi;
78  }
79  angle = std::min(angle, pi - angle);
80  return angle;
81 }
82 /*end of angle util*/
83 
84 /*other util*/
85 template <typename T>
86 T GetJaccardIndex(const T *bbox_ref, const T &x_min, const T &y_min,
87  const T &x_max, const T &y_max) {
88  T overlap_x = std::min(bbox_ref[2], x_max) - std::max(bbox_ref[0], x_min);
89  T overlap_y = std::min(bbox_ref[3], y_max) - std::max(bbox_ref[1], y_min);
90  if (overlap_y <= (T)0 || overlap_x <= (T)0) {
91  return (T)0;
92  }
93  T inter_area = overlap_x * overlap_y;
94  T union_area = (y_max - y_min) * (x_max - x_min) +
95  (bbox_ref[3] - bbox_ref[1]) * (bbox_ref[2] - bbox_ref[0]) -
96  inter_area;
97  return inter_area * common::IRec(union_area);
98 }
99 
100 template <typename T>
101 void GenRotMatrix(const T &ry, T *rot) {
102  rot[0] = static_cast<T>(cos(ry));
103  rot[2] = static_cast<T>(sin(ry));
104  rot[4] = static_cast<T>(1.0f);
105  rot[6] = static_cast<T>(-sin(ry));
106  rot[8] = static_cast<T>(cos(ry));
107  rot[1] = rot[3] = rot[5] = rot[7] = static_cast<T>(0);
108 }
109 
110 template <typename T>
111 void GenCorners(T h, T w, T l, T *x_cor, T *y_cor, T *z_cor) {
112  T half_w = static_cast<T>(w * 0.5f);
113  T half_l = static_cast<T>(l * 0.5f);
114  y_cor[0] = y_cor[1] = y_cor[2] = y_cor[3] = (T)0;
115  y_cor[4] = y_cor[5] = y_cor[6] = y_cor[7] = -h;
116  x_cor[0] = x_cor[4] = half_l;
117  z_cor[0] = z_cor[4] = half_w;
118  x_cor[1] = x_cor[5] = half_l;
119  z_cor[1] = z_cor[5] = -half_w;
120  x_cor[2] = x_cor[6] = -half_l;
121  z_cor[2] = z_cor[6] = -half_w;
122  x_cor[3] = x_cor[7] = -half_l;
123  z_cor[3] = z_cor[7] = half_w;
124 }
125 
126 template <typename T>
127 bool Occlude(const T *bbox1, const T &h1, const T *bbox2, const T &h2) {
128  T overlap_x = std::min(bbox1[2], bbox2[2]) - std::max(bbox1[0], bbox2[0]);
129  T overlap_y = std::min(bbox1[3], bbox2[3]) - std::max(bbox1[1], bbox2[1]);
130  if (overlap_y <= (T)0 || overlap_x <= (T)0) {
131  return false;
132  }
133  const T HEIGHT_BIG_MOT = static_cast<T>(3.0f);
134  const T OCC_RATIO = (T)0.1f;
135  T bh1 = bbox1[3] - bbox1[1];
136  T bh2 = bbox2[3] - bbox2[1];
137  T inter_area = overlap_x * overlap_y;
138  T area = bh2 * (bbox2[2] - bbox2[0]);
139  T occ_ratio = inter_area * common::IRec(area);
140  T thres_occ_ratio = h2 < HEIGHT_BIG_MOT ? 2 * OCC_RATIO : OCC_RATIO;
141  bool occ = occ_ratio > thres_occ_ratio &&
142  h1 * common::IRec(bh1) < h2 * common::IRec(bh2);
143  return occ;
144 }
145 
146 template <typename T>
147 void GetBboxFromPts(const T *pts, const int &n, T *bbox) {
148  bbox[0] = bbox[2] = pts[0];
149  bbox[1] = bbox[3] = pts[1];
150  int i2 = 2;
151  for (int i = 1; i < n; ++i) {
152  T x = pts[i2];
153  T y = pts[i2 + 1];
154  bbox[0] = std::min(bbox[0], x);
155  bbox[1] = std::min(bbox[1], y);
156  bbox[2] = std::max(bbox[2], x);
157  bbox[3] = std::max(bbox[3], y);
158  i2 += 2;
159  }
160 }
161 
162 template <typename T>
163 int GetMinIndexVec(const T *vec, const int &n) {
164  CHECK_GT(n, 0);
165  int index = 0;
166  T min_val = vec[0];
167  for (int i = 1; i < n; ++i) {
168  if (vec[i] < min_val) {
169  min_val = vec[i];
170  index = i;
171  }
172  }
173  return index;
174 }
175 
176 template <typename T>
177 T GetScoreViaRotDimensionCenter(const T *k_mat, int width, int height,
178  const T *bbox, const T *rot, const T *hwl,
179  const T *location, const bool &check_truncation,
180  T *bbox_res = nullptr, T *bbox_near = nullptr) {
181  T h = hwl[0];
182  T w = hwl[1];
183  T l = hwl[2];
184  T x_corners[8] = {0};
185  T y_corners[8] = {0};
186  T z_corners[8] = {0};
187  GenCorners(h, w, l, x_corners, y_corners, z_corners);
188 
189  T x_min = std::numeric_limits<float>::max();
190  T x_max = -std::numeric_limits<float>::max();
191  T y_min = std::numeric_limits<float>::max();
192  T y_max = -std::numeric_limits<float>::max();
193  T x_proj[3];
194  T x_box[3];
195  T pts_proj[16];
196  for (int i = 0; i < 8; ++i) {
197  x_box[0] = x_corners[i];
198  x_box[1] = y_corners[i];
199  x_box[2] = z_corners[i];
200  common::IProjectThroughKRt(k_mat, rot, location, x_box, x_proj);
201  x_proj[0] *= common::IRec(x_proj[2]);
202  x_proj[1] *= common::IRec(x_proj[2]);
203 
204  if (bbox_near != nullptr) {
205  int i2 = i * 2;
206  pts_proj[i2] = x_proj[0];
207  pts_proj[i2 + 1] = x_proj[1];
208  }
209  x_min = std::min(x_min, x_proj[0]);
210  x_max = std::max(x_max, x_proj[0]);
211  y_min = std::min(y_min, x_proj[1]);
212  y_max = std::max(y_max, x_proj[1]);
213  if (check_truncation) {
214  x_min = std::min(std::max(x_min, (T)0), (T)(width - 1));
215  x_max = std::min(std::max(x_max, (T)0), (T)(width - 1));
216  y_min = std::min(std::max(y_min, (T)0), (T)(height - 1));
217  y_max = std::min(std::max(y_max, (T)0), (T)(height - 1));
218  }
219  }
220  if (bbox_res != nullptr) {
221  bbox_res[0] = x_min;
222  bbox_res[1] = y_min;
223  bbox_res[2] = x_max;
224  bbox_res[3] = y_max;
225  }
226  if (bbox_near != nullptr) {
227  T bbox_front[4] = {0};
228  T bbox_rear[4] = {0};
229  std::swap(pts_proj[4], pts_proj[8]);
230  std::swap(pts_proj[5], pts_proj[9]);
231  std::swap(pts_proj[6], pts_proj[10]);
232  std::swap(pts_proj[7], pts_proj[11]);
233  GetBboxFromPts(pts_proj, 4, bbox_front);
234  GetBboxFromPts(pts_proj + 8, 4, bbox_rear);
235  if (bbox_rear[3] - bbox_rear[1] > bbox_front[3] - bbox_front[1]) {
236  memcpy(bbox_near, bbox_rear, sizeof(T) * 4);
237  } else {
238  memcpy(bbox_near, bbox_front, sizeof(T) * 4);
239  }
240  }
241  return GetJaccardIndex(bbox, x_min, y_min, x_max, y_max);
242 }
243 
244 template <typename T>
245 bool CheckXY(const T &x, const T &y, int width, int height) {
246  T max_x = static_cast<T>(width - 1);
247  T max_y = static_cast<T>(height - 1);
248  return x <= max_x && x >= (T)0 && y <= max_y && y >= (T)0;
249 }
250 
251 template <typename T>
252 void UpdateOffsetZ(T x_start, T z_start, T x_end, T z_end,
253  const std::pair<T, T> &range, T *z_offset) {
254  ACHECK(range.first < range.second);
255  if (x_start > x_end) {
256  std::swap(x_start, x_end);
257  std::swap(z_start, z_end);
258  }
259 
260  T x_check_l = std::max(x_start, range.first);
261  T x_check_r = std::min(x_end, range.second);
262  T overlap_x = x_check_r - x_check_l;
263  if (overlap_x < 1e-6) {
264  return;
265  }
266 
267  T dz_divide_dx = (z_end - z_start) * common::IRec(x_end - x_start);
268  T z_check_l = z_start + (x_check_l - x_start) * dz_divide_dx;
269  T z_check_r = z_start + (x_check_r - x_start) * dz_divide_dx;
270  T z_nearest = std::min(z_check_l, z_check_r);
271  if (z_nearest < *z_offset) {
272  *z_offset = z_nearest;
273  }
274 }
275 
276 template <typename T>
278  const T *plane, const T *pts_c,
279  const T *k_mat, int width, int height,
280  T ratio_x_over_z, T *dx_dz,
281  bool check_lowerbound = true) {
282  const T Z_RESOLUTION = static_cast<T>(1e-1);
283  const T Z_UNSTABLE_RATIO = static_cast<T>(0.3f);
284 
285  dx_dz[0] = dx_dz[1] = (T)0;
286  ACHECK(ls.pt_start[0] < ls.pt_end[0]);
287  if (!CheckXY(ls.pt_start[0], ls.pt_start[1], width, height) ||
288  !CheckXY(ls.pt_end[0], ls.pt_end[1], width, height)) {
289  return;
290  }
291  T pt_of_line_seg_l[3] = {0};
292  T pt_of_line_seg_r[3] = {0};
294  ls.pt_start, k_mat, plane, pt_of_line_seg_l);
296  ls.pt_end, k_mat, plane, pt_of_line_seg_r);
297  if (!is_front_l || !is_front_r) {
298  return;
299  }
300  ADEBUG << "l&r on-ground points: " << pt_of_line_seg_l[0] << ", "
301  << pt_of_line_seg_l[1] << ", " << pt_of_line_seg_l[2] << " | "
302  << pt_of_line_seg_r[0] << ", " << pt_of_line_seg_r[1] << ", "
303  << pt_of_line_seg_r[2];
304 
305  // get transform
306  T rot[9] = {0};
307  T t[3] = {0};
308  T pos[3] = {pt_of_line_seg_l[0], pt_of_line_seg_l[1], pt_of_line_seg_l[2]};
309  T v[3] = {pt_of_line_seg_r[0] - pt_of_line_seg_l[0],
310  pt_of_line_seg_r[1] - pt_of_line_seg_l[1],
311  pt_of_line_seg_r[2] - pt_of_line_seg_l[2]};
312  T ry = static_cast<T>(-atan2(v[2], v[0]));
313  GenRotMatrix(ry, rot);
315  common::IScale3(pos, (T)-1);
316  common::IMultAx3x3(rot, pos, t);
317  ADEBUG << "ry: " << ry;
318 
319  T l[3] = {0};
320  T pt1[3] = {0};
321  T pt2[3] = {ratio_x_over_z, (T)0, (T)1};
322  T pt1_local[3] = {0};
323  T pt2_local[3] = {0};
324 
325  // transform to local birdview coordinates
326  std::pair<T, T> range;
327  range.first = 0;
328  range.second = common::ISqrt(common::ISqr(v[0]) + common::ISqr(v[2]));
329  T pts_local[12] = {0};
330  common::IProjectThroughExtrinsic(rot, t, pts_c, pts_local);
331  common::IProjectThroughExtrinsic(rot, t, pts_c + 3, pts_local + 3);
332  common::IProjectThroughExtrinsic(rot, t, pts_c + 6, pts_local + 6);
333  common::IProjectThroughExtrinsic(rot, t, pts_c + 9, pts_local + 9);
334 
335  common::IProjectThroughExtrinsic(rot, t, pt1, pt1_local);
336  common::IProjectThroughExtrinsic(rot, t, pt2, pt2_local);
337  T x[2] = {pt1_local[0], pt1_local[2]};
338  T xp[2] = {pt2_local[0], pt2_local[2]};
339  common::ILineFit2d(x, xp, l);
340 
341  T zs[4] = {pts_local[2], pts_local[5], pts_local[8], pts_local[11]};
342  T z_offset = static_cast<T>(0);
343  bool all_positive = zs[0] > 0.0f && zs[1] > 0.f && zs[2] > 0.f && zs[3] > 0.f;
344  if (all_positive) {
345  z_offset = std::min(zs[0], std::min(zs[1], std::min(zs[2], zs[3])));
346  } else {
347  z_offset = std::max(zs[0], std::max(zs[1], std::max(zs[2], zs[3])));
348  T xs[4] = {pts_local[0], pts_local[3], pts_local[6], pts_local[9]};
349  // 1 -> 2
350  UpdateOffsetZ(xs[0], zs[0], xs[1], zs[1], range, &z_offset);
351  // 2 -> 3
352  UpdateOffsetZ(xs[1], zs[1], xs[2], zs[2], range, &z_offset);
353  // 3 -> 4
354  UpdateOffsetZ(xs[2], zs[2], xs[3], zs[3], range, &z_offset);
355  // 4 -> 1
356  UpdateOffsetZ(xs[3], zs[3], xs[0], zs[0], range, &z_offset);
357  }
358  if (z_offset < Z_RESOLUTION && z_offset > -Z_RESOLUTION) {
359  return;
360  }
361 
362  // judge & convert back to camera coordinates
363  if (z_offset > static_cast<T>(0.0f) && check_lowerbound) {
364  return;
365  }
366 
367  T center_c[3] = {0};
368  center_c[0] = (pts_c[0] + pts_c[3] + pts_c[6] + pts_c[9]) / 4;
369  center_c[2] = (pts_c[2] + pts_c[5] + pts_c[8] + pts_c[11]) / 4;
370  T z_avg = center_c[2];
371 
372  T dz_local = -z_offset;
373  T dx_local =
374  -l[1] * dz_local * common::IRec(l[0]); /*enforce to be along the ray*/
375 
376  T center_local[3] = {0};
377  common::IProjectThroughExtrinsic(rot, t, center_c, center_local);
378  center_local[0] += dx_local;
379  center_local[1] = 0;
380  center_local[2] += dz_local;
381  T center_local_to_c[3] = {0};
382  common::ISub3(t, center_local);
383  common::IMultAtx3x3(rot, center_local, center_local_to_c);
384  dx_dz[0] = center_local_to_c[0] - center_c[0];
385  dx_dz[1] = center_local_to_c[2] - center_c[2];
386 
387  T dz_max = z_avg * Z_UNSTABLE_RATIO;
388  if (z_offset > static_cast<T>(0.0f) && std::abs(dx_dz[1]) > dz_max) {
389  dx_dz[0] = dx_dz[1] = 0;
390  }
391 }
392 
393 } // namespace camera
394 } // namespace perception
395 } // namespace apollo
float sin(Angle16 a)
int GetMinIndexVec(const T *vec, const int &n)
Definition: twod_threed_util.h:163
void IProjectThroughKRt(const T *K, const T *R, const T *t, const T *X, T *x)
Definition: i_util.h:121
#define ACHECK(cond)
Definition: log.h:80
LineSegment2D(const LineSegment2D &ls)
Definition: twod_threed_util.h:44
PlanningContext is the runtime context in planning. It is persistent across multiple frames...
Definition: atomic_hash_map.h:25
float IRec(float a)
Definition: i_basic.h:69
LineSegment2D(const T &x_start, const T &y_start, const T &x_end, const T &y_end)
Definition: twod_threed_util.h:37
float ISqr(float a)
Definition: i_basic.h:103
void UpdateOffsetZ(T x_start, T z_start, T x_end, T z_end, const std::pair< T, T > &range, T *z_offset)
Definition: twod_threed_util.h:252
T abs(const T &x)
Definition: misc.h:48
const double PI
Definition: const_var.h:77
T GetJaccardIndex(const T *bbox_ref, const T &x_min, const T &y_min, const T &x_max, const T &y_max)
Definition: twod_threed_util.h:86
void IProjectThroughExtrinsic(const T *R, const T *t, const T *X, T *x)
Definition: i_util.h:103
void ISub3(const T x[3], const T y[3], T z[3])
Definition: i_blas.h:1405
void ITranspose3x3(T A[9])
Definition: i_blas.h:4250
T GetSharpAngle(const T &a, const T &b)
Definition: twod_threed_util.h:72
void IMultAx3x3(const T A[9], const T x[3], T Ax[3])
Definition: i_blas.h:4358
#define ADEBUG
Definition: log.h:41
void ILineFit2d(const T *x, const T *xp, T *l)
Definition: i_line.h:68
bool CheckXY(const T &x, const T &y, int width, int height)
Definition: twod_threed_util.h:245
void GenCorners(T h, T w, T l, T *x_cor, T *y_cor, T *z_cor)
Definition: twod_threed_util.h:111
void GenRotMatrix(const T &ry, T *rot)
Definition: twod_threed_util.h:101
T CalAngleDiff(const T a1, const T a2)
Definition: twod_threed_util.h:61
Definition: twod_threed_util.h:33
float cos(Angle16 a)
float ISqrt(float a)
Definition: i_basic.h:76
bool IBackprojectPlaneIntersectionCanonical(const T *x, const T *K, const T *pi, T *X)
Definition: i_util.h:197
T GetScoreViaRotDimensionCenter(const T *k_mat, int width, int height, const T *bbox, const T *rot, const T *hwl, const T *location, const bool &check_truncation, T *bbox_res=nullptr, T *bbox_near=nullptr)
Definition: twod_threed_util.h:177
void GetDxDzForCenterFromGroundLineSeg(const LineSegment2D< T > &ls, const T *plane, const T *pts_c, const T *k_mat, int width, int height, T ratio_x_over_z, T *dx_dz, bool check_lowerbound=true)
Definition: twod_threed_util.h:277
T pt_end[2]
Definition: twod_threed_util.h:35
bool Occlude(const T *bbox1, const T &h1, const T *bbox2, const T &h2)
Definition: twod_threed_util.h:127
void IScale3(T x[3], T sf)
Definition: i_blas.h:1868
void operator=(const LineSegment2D &ls)
Definition: twod_threed_util.h:50
void IMultAtx3x3(const T A[9], const T x[3], T Atx[3])
Definition: i_blas.h:4369
void GetBboxFromPts(const T *pts, const int &n, T *bbox)
Definition: twod_threed_util.h:147
T pt_start[2]
Definition: twod_threed_util.h:34