Apollo 10.0
自动驾驶开放平台
twod_threed_util.h
浏览该文件的文档.
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
27namespace apollo {
28namespace perception {
29namespace camera {
30
31/*auxiliary data structure*/
32template <typename T>
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*/
60template <typename T>
61T CalAngleDiff(const T a1, const T a2) {
62 T diff1 = a1 - a2;
63 diff1 = diff1 < 0 ? -diff1 : diff1;
64 T diff2 = a1 - a2 + algorithm::Constant<T>::PI() * 2;
65 diff2 = diff2 < 0 ? -diff2 : diff2;
66 T diff3 = a1 - a2 - algorithm::Constant<T>::PI() * 2;
67 diff3 = diff3 < 0 ? -diff3 : diff3;
68 return std::min<T>(std::min<T>(diff1, diff2), diff3);
69}
70
71template <typename T>
72inline T GetSharpAngle(const T &a, const T &b) {
73 /*a and b are in [-pi, pi)*/
74 const T pi = algorithm::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*/
85template <typename T>
86T 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 * algorithm::IRec(union_area);
98}
99
100template <typename T>
101void 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
110template <typename T>
111void 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
126template <typename T>
127bool 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 * algorithm::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 * algorithm::IRec(bh1) < h2 * algorithm::IRec(bh2);
143 return occ;
144}
145
146template <typename T>
147void 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
162template <typename T>
163int 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
176template <typename T>
177T 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 algorithm::IProjectThroughKRt(k_mat, rot, location, x_box, x_proj);
201 x_proj[0] *= algorithm::IRec(x_proj[2]);
202 x_proj[1] *= algorithm::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
244template <typename T>
245bool 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
251template <typename T>
252void 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) * algorithm::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
276template <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 algorithm::IScale3(pos, (T)-1);
316 algorithm::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 = algorithm::ISqrt(
329 algorithm::ISqr(v[0]) + algorithm::ISqr(v[2]));
330 T pts_local[12] = {0};
331 algorithm::IProjectThroughExtrinsic(rot, t, pts_c, pts_local);
332 algorithm::IProjectThroughExtrinsic(rot, t, pts_c + 3, pts_local + 3);
333 algorithm::IProjectThroughExtrinsic(rot, t, pts_c + 6, pts_local + 6);
334 algorithm::IProjectThroughExtrinsic(rot, t, pts_c + 9, pts_local + 9);
335
336 algorithm::IProjectThroughExtrinsic(rot, t, pt1, pt1_local);
337 algorithm::IProjectThroughExtrinsic(rot, t, pt2, pt2_local);
338 T x[2] = {pt1_local[0], pt1_local[2]};
339 T xp[2] = {pt2_local[0], pt2_local[2]};
340 algorithm::ILineFit2d(x, xp, l);
341
342 T zs[4] = {pts_local[2], pts_local[5], pts_local[8], pts_local[11]};
343 T z_offset = static_cast<T>(0);
344 bool all_positive = zs[0] > 0.0f && zs[1] > 0.f && zs[2] > 0.f && zs[3] > 0.f;
345 if (all_positive) {
346 z_offset = std::min(zs[0], std::min(zs[1], std::min(zs[2], zs[3])));
347 } else {
348 z_offset = std::max(zs[0], std::max(zs[1], std::max(zs[2], zs[3])));
349 T xs[4] = {pts_local[0], pts_local[3], pts_local[6], pts_local[9]};
350 // 1 -> 2
351 UpdateOffsetZ(xs[0], zs[0], xs[1], zs[1], range, &z_offset);
352 // 2 -> 3
353 UpdateOffsetZ(xs[1], zs[1], xs[2], zs[2], range, &z_offset);
354 // 3 -> 4
355 UpdateOffsetZ(xs[2], zs[2], xs[3], zs[3], range, &z_offset);
356 // 4 -> 1
357 UpdateOffsetZ(xs[3], zs[3], xs[0], zs[0], range, &z_offset);
358 }
359 if (z_offset < Z_RESOLUTION && z_offset > -Z_RESOLUTION) {
360 return;
361 }
362
363 // judge & convert back to camera coordinates
364 if (z_offset > static_cast<T>(0.0f) && check_lowerbound) {
365 return;
366 }
367
368 T center_c[3] = {0};
369 center_c[0] = (pts_c[0] + pts_c[3] + pts_c[6] + pts_c[9]) / 4;
370 center_c[2] = (pts_c[2] + pts_c[5] + pts_c[8] + pts_c[11]) / 4;
371 T z_avg = center_c[2];
372
373 T dz_local = -z_offset;
374 T dx_local =
375 -l[1] * dz_local * algorithm::IRec(l[0]); /*enforce to be along the ray*/
376
377 T center_local[3] = {0};
378 algorithm::IProjectThroughExtrinsic(rot, t, center_c, center_local);
379 center_local[0] += dx_local;
380 center_local[1] = 0;
381 center_local[2] += dz_local;
382 T center_local_to_c[3] = {0};
383 algorithm::ISub3(t, center_local);
384 algorithm::IMultAtx3x3(rot, center_local, center_local_to_c);
385 dx_dz[0] = center_local_to_c[0] - center_c[0];
386 dx_dz[1] = center_local_to_c[2] - center_c[2];
387
388 T dz_max = z_avg * Z_UNSTABLE_RATIO;
389 if (z_offset > static_cast<T>(0.0f) && std::abs(dx_dz[1]) > dz_max) {
390 dx_dz[0] = dx_dz[1] = 0;
391 }
392}
393
394} // namespace camera
395} // namespace perception
396} // namespace apollo
#define ACHECK(cond)
Definition log.h:80
#define ADEBUG
Definition log.h:41
void IProjectThroughExtrinsic(const T *R, const T *t, const T *X, T *x)
Definition i_util.h:103
void IMultAx3x3(const T A[9], const T x[3], T Ax[3])
Definition i_blas.h:4358
void IMultAtx3x3(const T A[9], const T x[3], T Atx[3])
Definition i_blas.h:4369
bool IBackprojectPlaneIntersectionCanonical(const T *x, const T *K, const T *pi, T *X)
Definition i_util.h:197
void ILineFit2d(const T *x, const T *xp, T *l)
Definition i_line.h:68
void IProjectThroughKRt(const T *K, const T *R, const T *t, const T *X, T *x)
Definition i_util.h:121
void IScale3(T x[3], T sf)
Definition i_blas.h:1868
void ISub3(const T x[3], const T y[3], T z[3])
Definition i_blas.h:1405
void GenCorners(T h, T w, T l, T *x_cor, T *y_cor, T *z_cor)
int GetMinIndexVec(const T *vec, const int &n)
void GenRotMatrix(const T &ry, T *rot)
bool CheckXY(const T &x, const T &y, int width, int height)
T CalAngleDiff(const T a1, const T a2)
T GetSharpAngle(const T &a, const T &b)
void UpdateOffsetZ(T x_start, T z_start, T x_end, T z_end, const std::pair< T, T > &range, T *z_offset)
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)
T GetJaccardIndex(const T *bbox_ref, const T &x_min, const T &y_min, const T &x_max, const T &y_max)
bool Occlude(const T *bbox1, const T &h1, const T *bbox2, const T &h2)
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)
void GetBboxFromPts(const T *pts, const int &n, T *bbox)
class register implement
Definition arena_queue.h:37
LineSegment2D(const T &x_start, const T &y_start, const T &x_end, const T &y_end)
void operator=(const LineSegment2D &ls)