Apollo 11.0
自动驾驶开放平台
obj_mapper.cc
浏览该文件的文档.
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 *****************************************************************************/
17
18#include <limits>
19#include <map>
20
21namespace apollo {
22namespace perception {
23namespace camera {
24
26 nr_bins_z = 15;
27 nr_bins_ry = 36;
28 boundary_len = 20;
29 max_nr_iter = 10;
30
31 small_bbox_height = 50.0f;
32 factor_small = 0.6f;
33 learning_r = 0.7f;
34 reproj_err = 4 * sqrtf(2.0f);
35 rz_ratio = 0.1f;
36 abnormal_h_veh = 0.8f;
37 stable_w = 0.5f;
38 occ_ratio = 0.9f;
39 depth_min = 0.1f;
40 dist_far = 100.0f;
41 eps_mapper = 1e-5f;
42
43 iou_suc = 0.5f;
44 iou_high = 0.7f;
46}
47
48bool ObjMapper::SolveCenterFromNearestVerticalEdge(const float *bbox,
49 const float *hwl, float ry,
50 float *center,
51 float *center_2d) const {
52 center[0] = center[1] = center[2] = 0.0f;
53 float height_bbox = bbox[3] - bbox[1];
54 float width_bbox = bbox[2] - bbox[0];
55 if (width_bbox <= 0.0f || height_bbox <= 0.0f) {
56 AERROR << "width or height of bbox is 0";
57 return false;
58 }
59
60 if (algorithm::IRound(bbox[3]) >= height_ - 1) {
61 height_bbox /= params_.occ_ratio;
62 }
63
64 float f = (k_mat_[0] + k_mat_[4]) / 2;
65 float depth = f * hwl[0] * algorithm::IRec(height_bbox);
66
67 // compensate from the nearest vertical edge to center
68 const float PI = algorithm::Constant<float>::PI();
69 float theta_bbox = static_cast<float>(atan(hwl[1] * algorithm::IRec(hwl[2])));
70 float radius_bbox = algorithm::ISqrt(algorithm::ISqr(hwl[2] / 2) +
71 algorithm::ISqr(hwl[1] / 2));
72
73 float abs_ry = fabsf(ry);
74 float theta_z = std::min(abs_ry, PI - abs_ry) + theta_bbox;
75 theta_z = std::min(theta_z, PI - theta_z);
76 depth += static_cast<float>(fabs(radius_bbox * sin(theta_z)));
77
78 // back-project to solve center
79 center_2d[0] = (bbox[0] + bbox[2]) / 2;
80 center_2d[1] = (bbox[1] + bbox[3]) / 2;
81 if (hwl[1] > params_.stable_w) {
82 GetCenter(bbox, depth, ry, hwl, center, center_2d);
83 } else {
84 center[2] = depth;
85 UpdateCenterViaBackProjectZ(bbox, hwl, center_2d, center);
86 }
87
88 return center[2] > params_.depth_min;
89}
90
91bool ObjMapper::Solve3dBboxGivenOneFullBboxDimensionOrientation(
92 const float *bbox, const float *hwl, float *ry, float *center) {
93 const float PI = algorithm::Constant<float>::PI();
94 const float PI_HALF = PI / 2;
95 const float small_angle_diff =
97 float center_2d[2] = {0};
98 bool success =
99 SolveCenterFromNearestVerticalEdge(bbox, hwl, *ry, center, center_2d);
100 float min_x = static_cast<float>(params_.boundary_len);
101 float min_y = static_cast<float>(params_.boundary_len);
102 float max_x = static_cast<float>(width_ - params_.boundary_len);
103 float max_y = static_cast<float>(height_ - params_.boundary_len);
104 bool truncated = bbox[0] <= min_x || bbox[2] >= max_x || bbox[1] <= min_y ||
105 bbox[3] >= max_y;
106 float dist_rough =
107 sqrtf(algorithm::ISqr(center[0]) + algorithm::ISqr(center[2]));
108 bool ry_pred_is_not_reliable = dist_rough > params_.dist_far &&
109 bbox[3] - bbox[1] < params_.small_bbox_height;
110 if (ry_pred_is_not_reliable || std::abs(*ry - PI_HALF) < small_angle_diff ||
111 std::abs(*ry + PI_HALF) < small_angle_diff) {
112 *ry = *ry > 0.0f ? PI_HALF : -PI_HALF;
113 }
114 if (!truncated) {
115 PostRefineOrientation(bbox, hwl, center, ry);
116 success =
117 SolveCenterFromNearestVerticalEdge(bbox, hwl, *ry, center, center_2d);
118 PostRefineZ(bbox, hwl, center_2d, *ry, center);
119 } else {
120 FillRyScoreSingleBin(*ry);
121 }
122 return success &&
123 GetProjectionScore(*ry, bbox, hwl, center, true) > params_.iou_suc;
124}
125
126bool ObjMapper::Solve3dBbox(const ObjMapperOptions &options, float center[3],
127 float hwl[3], float *ry) {
128 // set default value for variance
130 float var_yaw = 0.0f;
131 float var_z = 0.0f;
132
133 // get input from options
134 memcpy(hwl, options.hwl, sizeof(float) * 3);
135 float bbox[4] = {0};
136 memcpy(bbox, options.bbox, sizeof(float) * 4);
137 *ry = options.ry;
138 bool check_dimension = options.check_dimension;
139 int type_min_vol_index = options.type_min_vol_index;
140
141 // check input hwl insanity
142 if (options.is_veh && check_dimension) {
143 assert(type_min_vol_index >= 0);
144 const std::vector<float> &kVehHwl = object_template_manager_->VehHwl();
145 const float *tmplt_with_min_vol = &kVehHwl[type_min_vol_index];
146 float min_tmplt_vol =
147 tmplt_with_min_vol[0] * tmplt_with_min_vol[1] * tmplt_with_min_vol[2];
148 float shrink_ratio_vol = algorithm::ISqr(sqrtf(params_.iou_high));
149 shrink_ratio_vol *= shrink_ratio_vol;
150 // float shrink_ratio_vol = sqrt(params_.iou_high);
151 if (hwl[0] < params_.abnormal_h_veh ||
152 hwl[0] * hwl[1] * hwl[2] < min_tmplt_vol * shrink_ratio_vol) {
153 memcpy(hwl, tmplt_with_min_vol, sizeof(float) * 3);
154 } else {
155 float hwl_tmplt[3] = {hwl[0], hwl[1], hwl[2]};
156 int tmplt_index = -1;
158 hwl_tmplt, &tmplt_index);
159 float thres_min_score = shrink_ratio_vol;
160
161 const int kNrDimPerTmplt = object_template_manager_->NrDimPerTmplt();
162 bool search_success = score > thres_min_score;
163 bool is_same_type = (type_min_vol_index / kNrDimPerTmplt) == tmplt_index;
164 const std::map<TemplateIndex, int> &kLookUpTableMinVolumeIndex =
166 bool is_car_pred =
167 type_min_vol_index ==
168 kLookUpTableMinVolumeIndex.at(TemplateIndex::CAR_MIN_VOLUME_INDEX);
169
170 bool hwl_is_reliable = search_success && is_same_type;
171 if (hwl_is_reliable) {
172 memcpy(hwl, hwl_tmplt, sizeof(float) * 3);
173 } else if (is_car_pred) {
174 const float *tmplt_with_median_vol =
175 tmplt_with_min_vol + kNrDimPerTmplt;
176 memcpy(hwl, tmplt_with_median_vol, sizeof(float) * 3);
177 }
178 }
179 }
180
181 // call 3d solver
182 bool success =
183 Solve3dBboxGivenOneFullBboxDimensionOrientation(bbox, hwl, ry, center);
184
185 // calculate variance for yaw & z
186 float yaw_score_mean =
187 algorithm::IMean(ry_score_.data(), static_cast<int>(ry_score_.size()));
188 float yaw_score_sdv = algorithm::ISdv(ry_score_.data(), yaw_score_mean,
189 static_cast<int>(ry_score_.size()));
190 var_yaw =
191 algorithm::ISqrt(algorithm::IRec(yaw_score_sdv + params_.eps_mapper));
192
193 float z = center[2];
194 float rz = z * params_.rz_ratio;
195 float nr_bins_z = static_cast<float>(params_.nr_bins_z);
196 std::vector<float> buffer(static_cast<size_t>(2 * nr_bins_z), 0);
197 float *score_z = buffer.data();
198 float dz = 2 * rz / nr_bins_z;
199 float z_start = std::max(z - rz, params_.depth_min);
200 float z_end = z + rz;
201 int count_z_test = 0;
202 for (float z_test = z_start; z_test <= z_end; z_test += dz) {
203 float center_test[3] = {center[0], center[1], center[2]};
204 float sf = z_test * algorithm::IRec(center_test[2]);
205 algorithm::IScale3(center_test, sf);
206 float score_test = GetProjectionScore(*ry, bbox, hwl, center_test);
207 score_z[count_z_test++] = score_test;
208 }
209 float z_score_mean = algorithm::IMean(score_z, count_z_test);
210 float z_score_sdv = algorithm::ISdv(score_z, z_score_mean, count_z_test);
211 var_z = algorithm::ISqr(algorithm::IRec(z_score_sdv + params_.eps_mapper));
212
213 // fill the position_uncertainty_ and orientation_variance_
214 orientation_variance_(0) = var_yaw;
215 float bbox_cx = (bbox[0] + bbox[2]) / 2;
216 float focal = (k_mat_[0] + k_mat_[4]) / 2;
217 float sf_z_to_x = fabsf(bbox_cx - k_mat_[2]) * algorithm::IRec(focal);
218 float var_x = var_z * algorithm::ISqr(sf_z_to_x);
219 float var_xz = sf_z_to_x * var_z;
220 position_uncertainty_(0, 0) = var_x;
221 position_uncertainty_(2, 2) = var_z;
222 position_uncertainty_(0, 2) = position_uncertainty_(2, 0) = var_xz;
223 return success;
224}
225
226void ObjMapper::PostRefineOrientation(const float *bbox, const float *hwl,
227 const float *center, float *ry) {
228 const int kNrBinsRy = static_cast<int>(ry_score_.size());
229 const float PI = algorithm::Constant<float>::PI();
230 const float PI_HALF = PI * 0.5f;
231 const float D_RY = 2 * PI / static_cast<float>(kNrBinsRy);
232
233 float ry_test = -PI;
234 float ry_best = -PI;
235 float score_best = 0.0f;
236 float score_cur = GetProjectionScore(*ry, bbox, hwl, center, true);
237 int count_bin = 0;
238 while (ry_test < PI - params_.eps_mapper) {
239 if (CalAngleDiff(ry_test, *ry) > PI_HALF) {
240 ry_test += D_RY;
241 ry_score_[count_bin++ % kNrBinsRy] = 0.0f;
242 continue;
243 }
244
245 float score_test = GetProjectionScore(ry_test, bbox, hwl, center, true);
246 if (score_test > score_best) {
247 score_best = score_test;
248 ry_best = ry_test;
249 }
250 ry_test += D_RY;
251 ry_score_[count_bin++ % kNrBinsRy] = score_test;
252 }
253 algorithm::IUnitize(ry_score_.data(), kNrBinsRy);
254 if (score_best > params_.iou_high && score_cur < params_.iou_suc) {
255 *ry = ry_best;
256 }
257
258 float bbox_res[4] = {0};
259 float score_final =
260 GetProjectionScore(*ry, bbox, hwl, center, true, bbox_res);
261 if (score_final > params_.iou_high) {
262 return;
263 } else if (bbox[2] - bbox[0] <
264 (bbox_res[2] - bbox_res[0]) * params_.factor_small) {
265 *ry = *ry > 0 ? PI_HALF : -PI_HALF;
266 FillRyScoreSingleBin(*ry);
267 } else if ((bbox[2] - bbox[0]) * params_.factor_small >
268 bbox_res[2] - bbox_res[0]) {
269 *ry = 0.0f;
270 FillRyScoreSingleBin(*ry);
271 }
272}
273
274void ObjMapper::GetCenter(const float *bbox, const float &z_ref,
275 const float &ry, const float *hwl, float *center,
276 float *x) const {
277 float x_target[2] = {(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2};
278 const float kMinCost = params_.reproj_err;
279 const float EPS_COST_DELTA = params_.eps_mapper;
280 const float LR = params_.learning_r;
281 const int MAX_ITERATION = params_.max_nr_iter;
282
283 float cost_pre = 2.0f * static_cast<float>(width_);
284 float cost_delta = 0.0f;
285 float center_test[3] = {0};
286 float rot[9] = {0};
287 GenRotMatrix(ry, rot);
288 int iter = 1;
289 bool stop = false;
290 float h = hwl[0];
291 float w = hwl[1];
292 float l = hwl[2];
293 float x_corners[8] = {0};
294 float y_corners[8] = {0};
295 float z_corners[8] = {0};
296 GenCorners(h, w, l, x_corners, y_corners, z_corners);
297
298 float x_max_flt = static_cast<float>(width_ - 1);
299 float y_max_flt = static_cast<float>(height_ - 1);
300
301 // std::cout << "start to iteratively search the center..." << std::endl;
302 while (!stop) {
303 algorithm::IBackprojectCanonical(x, k_mat_, z_ref, center_test);
304 center_test[1] += hwl[0] / 2;
305 float x_min = std::numeric_limits<float>::max();
306 float x_max = -std::numeric_limits<float>::max();
307 float y_min = std::numeric_limits<float>::max();
308 float y_max = -std::numeric_limits<float>::max();
309 float x_proj[3] = {0};
310
311 for (int i = 0; i < 8; ++i) {
312 // bbox from x_proj
313 float x_box[3] = {x_corners[i], y_corners[i], z_corners[i]};
314 algorithm::IProjectThroughKRt(k_mat_, rot, center_test, x_box, x_proj);
315 x_proj[0] *= algorithm::IRec(x_proj[2]);
316 x_proj[1] *= algorithm::IRec(x_proj[2]);
317 x_min = std::min(x_min, x_proj[0]);
318 x_max = std::max(x_max, x_proj[0]);
319 y_min = std::min(y_min, x_proj[1]);
320 y_max = std::max(y_max, x_proj[1]);
321
322 // truncation processing
323 x_min = std::min(std::max(x_min, 0.0f), x_max_flt);
324 x_max = std::min(std::max(x_max, 0.0f), x_max_flt);
325 y_min = std::min(std::max(y_min, 0.0f), y_max_flt);
326 y_max = std::min(std::max(y_max, 0.0f), y_max_flt);
327 }
328 float x_cur[2] = {(x_min + x_max) / 2, (y_min + y_max) / 2};
329 float cost_cur = algorithm::ISqrt(algorithm::ISqr(x_cur[0] - x_target[0]) +
330 algorithm::ISqr(x_cur[1] - x_target[1]));
331
332 if (cost_cur >= cost_pre) {
333 stop = true;
334 } else {
335 memcpy(center, center_test, sizeof(float) * 3);
336 cost_delta = (cost_pre - cost_cur) / cost_pre;
337 cost_pre = cost_cur;
338 x[0] += (x_target[0] - x_cur[0]) * LR;
339 x[1] += (x_target[1] - x_cur[1]) * LR;
340 ++iter;
341 stop = iter >= MAX_ITERATION || cost_delta < EPS_COST_DELTA ||
342 cost_pre < kMinCost;
343 }
344 }
345}
346
347} // namespace camera
348} // namespace perception
349} // namespace apollo
double f
void set_default_variance()
Set the default variance object
Definition obj_mapper.h:81
ObjectTemplateManager * object_template_manager_
Definition obj_mapper.h:296
bool Solve3dBbox(const ObjMapperOptions &options, float center[3], float hwl[3], float *ry)
Calculate 3d result
const std::map< TemplateIndex, int > & LookUpTableMinVolumeIndex()
float VehObjHwlBySearchTemplates(float *hwl, int *index=nullptr, bool *is_flip=nullptr)
#define AERROR
Definition log.h:44
float IDegreeToRadians(float d)
Definition i_basic.h:266
T IMean(const T *x, int n)
Definition i_blas.h:2434
void IUnitize(double *x, int n)
Definition i_blas.h:2907
T ISdv(const T *x, T mean, int n)
Definition i_blas.h:2500
void IProjectThroughKRt(const T *K, const T *R, const T *t, const T *X, T *x)
Definition i_util.h:121
void IBackprojectCanonical(const T *x, const T *K, T depth, T *X)
Definition i_util.h:164
void IScale3(T x[3], T sf)
Definition i_blas.h:1868
void GenCorners(T h, T w, T l, T *x_cor, T *y_cor, T *z_cor)
void GenRotMatrix(const T &ry, T *rot)
T CalAngleDiff(const T a1, const T a2)
class register implement
Definition arena_queue.h:37
#define PI