Apollo 11.0
自动驾驶开放平台
singlestage_transformer.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2020 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 <algorithm>
19#include <limits>
20
21#include "cyber/common/file.h"
22#include "cyber/common/log.h"
28
29namespace apollo {
30namespace perception {
31namespace camera {
32
34 max_nr_iter = 10;
35 learning_rate = 0.7f;
36 k_min_cost = 4 * sqrtf(2.0f);
37 eps_cost = 1e-5f;
38}
39
41 std::string config_file =
42 GetConfigFile(options.config_path, options.config_file);
43
44 if (!cyber::common::GetProtoFromFile(config_file, &singlestage_param_)) {
45 AERROR << "Read config failed: " << config_file;
46 return false;
47 }
48 AINFO << "Load transformer parameters from " << config_file
49 << " \nmin dimension: " << singlestage_param_.min_dimension_val()
50 << " \ndo template search: " << singlestage_param_.check_dimension();
51
52 return true;
53}
54
55void SingleStageTransformer::FillResults(
56 float object_center[3], float dimension_hwl[3], float rotation_y,
57 const Eigen::Affine3d &camera2world_pose, float theta_ray,
58 base::ObjectPtr obj) {
59 if (obj == nullptr) {
60 return;
61 }
62 object_center[1] -= dimension_hwl[0] / 2;
63 obj->camera_supplement.local_center(0) = object_center[0];
64 obj->camera_supplement.local_center(1) = object_center[1];
65 obj->camera_supplement.local_center(2) = object_center[2];
66 ADEBUG << "Obj id: " << obj->track_id;
67 ADEBUG << "Obj type: " << static_cast<int>(obj->sub_type);
68 ADEBUG << "Obj ori dimension: " << obj->size[2] << ", " << obj->size[1]
69 << ", " << obj->size[0];
70 obj->center(0) = static_cast<double>(object_center[0]);
71 obj->center(1) = static_cast<double>(object_center[1]);
72 obj->center(2) = static_cast<double>(object_center[2]);
73 obj->center = camera2world_pose * obj->center;
74
75 obj->size(2) = dimension_hwl[0];
76 obj->size(1) = dimension_hwl[1];
77 obj->size(0) = dimension_hwl[2];
78
79 obj->center_uncertainty(0) = static_cast<float>(0);
80 obj->center_uncertainty(1) = static_cast<float>(0);
81 obj->center_uncertainty(2) = static_cast<float>(0);
82
83 float theta = rotation_y;
84 Eigen::Vector3d dir = (camera2world_pose.matrix().block(0, 0, 3, 3) *
85 Eigen::Vector3d(cos(theta), 0, -sin(theta)));
86 obj->direction[0] = static_cast<float>(dir[0]);
87 obj->direction[1] = static_cast<float>(dir[1]);
88 obj->direction[2] = static_cast<float>(dir[2]);
89 obj->theta = static_cast<float>(atan2(dir[1], dir[0]));
90 obj->theta_variance = static_cast<float>(1.0);
91
92 obj->camera_supplement.alpha = rotation_y - theta_ray;
93
94 ADEBUG << "Dimension hwl: " << dimension_hwl[0] << ", " << dimension_hwl[1]
95 << ", " << dimension_hwl[2];
96 ADEBUG << "Obj ry:" << rotation_y;
97 ADEBUG << "Obj theta: " << obj->theta;
98 ADEBUG << "Obj center from transformer: " << obj->center.transpose();
99}
100
102 if (frame->detected_objects.empty()) {
103 ADEBUG << "No object input to transformer.";
104 return true;
105 }
106
107 const auto &camera_k_matrix = frame->camera_k_matrix;
108 float k_mat[9] = {0};
109 for (size_t i = 0; i < 3; i++) {
110 size_t i3 = i * 3;
111 for (size_t j = 0; j < 3; j++) {
112 k_mat[i3 + j] = camera_k_matrix(i, j);
113 }
114 }
115 ADEBUG << "Camera k matrix input to transformer: \n"
116 << k_mat[0] << ", " << k_mat[1] << ", " << k_mat[2] << "\n"
117 << k_mat[3] << ", " << k_mat[4] << ", " << k_mat[5] << "\n"
118 << k_mat[6] << ", " << k_mat[7] << ", " << k_mat[8] << "\n";
119 const auto &camera2world_pose = frame->camera2world_pose;
120
121 int height = frame->data_provider->src_height();
122 int width = frame->data_provider->src_width();
123 int nr_transformed_obj = 0;
124 const float PI = algorithm::Constant<float>::PI();
125 for (auto &obj : frame->detected_objects) {
126 if (obj == nullptr) {
127 ADEBUG << "Empty object input to transformer.";
128 continue;
129 }
130
131 // set object mapper options
132 float theta_ray = atan2(obj->camera_supplement.local_center[0],
133 obj->camera_supplement.local_center[2]);
134
135 // process
136 float object_center[3] = {obj->camera_supplement.local_center[0],
137 obj->camera_supplement.local_center[1],
138 obj->camera_supplement.local_center[2]};
139 float dimension_hwl[3] = {obj->size(2), obj->size(1), obj->size(0)};
140 float rotation_y =
141 theta_ray + static_cast<float>(obj->camera_supplement.alpha);
142 if (rotation_y < -PI) {
143 rotation_y += 2 * PI;
144 } else if (rotation_y >= PI) {
145 rotation_y -= 2 * PI;
146 }
147
148 // adjust center point
149 float bbox[4] = {0};
150 bbox[0] = obj->camera_supplement.box.xmin;
151 bbox[1] = obj->camera_supplement.box.ymin;
152 bbox[2] = obj->camera_supplement.box.xmax;
153 bbox[3] = obj->camera_supplement.box.ymax;
154 float center2d[3] = {0};
155
156 CenterPointFromBbox(bbox, dimension_hwl, rotation_y, object_center,
157 center2d, k_mat, height, width);
158 // fill back results
159 FillResults(object_center, dimension_hwl, rotation_y, camera2world_pose,
160 theta_ray, obj);
161
162 ++nr_transformed_obj;
163 }
164 return nr_transformed_obj > 0;
165}
166
167float SingleStageTransformer::CenterPointFromBbox(
168 const float *bbox, const float *hwl, float ry, float *center,
169 float *center_2d, const float *k_mat, int height, int width) {
170 float height_bbox = bbox[3] - bbox[1];
171 float width_bbox = bbox[2] - bbox[0];
172 if (width_bbox <= 0.0f || height_bbox <= 0.0f) {
173 AERROR << "Check predict bounding box, width or height is 0";
174 return false;
175 }
176
177 float f = (k_mat[0] + k_mat[4]) / 2;
178 float depth = f * hwl[0] * algorithm::IRec(height_bbox);
179
180 // Compensate from the nearest vertical edge to center
181 const float PI = algorithm::Constant<float>::PI();
182 float theta_bbox = static_cast<float>(atan(hwl[1] * algorithm::IRec(hwl[2])));
183 float radius_bbox = algorithm::ISqrt(algorithm::ISqr(hwl[2] / 2) +
184 algorithm::ISqr(hwl[1] / 2));
185
186 float abs_ry = fabsf(ry);
187 float theta_z = std::min(abs_ry, PI - abs_ry) + theta_bbox;
188 theta_z = std::min(theta_z, PI - theta_z);
189 depth += static_cast<float>(fabs(radius_bbox * sin(theta_z)));
190
191 // Back-project to solve center
192 float location[3] = {center[0], center[1] - hwl[0] / 2, center[2]};
193 algorithm::IProjectThroughIntrinsic(k_mat, location, center_2d);
194 center_2d[0] *= algorithm::IRec(center_2d[2]);
195 center_2d[1] *= algorithm::IRec(center_2d[2]);
196 if (fabsf(depth - center[2]) * algorithm::IRec(center[2]) > 0.1) {
197 ConstraintCenterPoint(bbox, center[2], ry, hwl, k_mat, center, center_2d,
198 height, width);
199 }
200 return depth;
201}
202
203void SingleStageTransformer::ConstraintCenterPoint(
204 const float *bbox, const float &z_ref, const float &ry, const float *hwl,
205 const float *k_mat, float *center, float *x, int height, int width) {
206 float center_2d_target[2] = {(bbox[0] + bbox[2]) / 2,
207 (bbox[1] + bbox[3]) / 2};
208 const float K_MIN_COST = params_.k_min_cost;
209 const float EPS_COST_DELTA = params_.eps_cost;
210 const float LEARNING_RATE = params_.learning_rate;
211 const int MAX_ITERATION = params_.max_nr_iter;
212
213 float cost_pre = 2.0f * static_cast<float>(width);
214 float cost_delta = 0.0f;
215 float center_temp[3] = {0};
216 float rot_y[9] = {0};
217
218 // Get rotation matrix rot_y
219 /*
220 cos(ry) 0 sin(ry)
221 R = 0 1 0
222 -sin(ry) 0 cos(ry)
223 */
224 GenRotMatrix(ry, rot_y);
225
226 int iter = 1;
227 bool stop = false;
228 float h = hwl[0];
229 float w = hwl[1];
230 float l = hwl[2];
231 float x_corners[8] = {0};
232 float y_corners[8] = {0};
233 float z_corners[8] = {0};
234
235 float x_upper_bound = static_cast<float>(width - 1);
236 float y_upper_bound = static_cast<float>(height - 1);
237
238 // Get dimension matrix
239 /*
240 l/2 l/2 -l/2 -l/2 l/2 l/2 -l/2 -l/2
241 D = 0 0 0 0 -h -h -h -h
242 w/2 -w/2 -w/2 w/2 w/2 -w/2 -w/2 -w/2
243 */
244 GenCorners(h, w, l, x_corners, y_corners, z_corners);
245 while (!stop) {
246 // Back project 3D center from image x and depth z_ref to camera center_temp
247 algorithm::IBackprojectCanonical(x, k_mat, z_ref, center_temp);
248 // From center to location
249 center_temp[1] += hwl[0] / 2;
250 float x_min = std::numeric_limits<float>::max();
251 float x_max = -std::numeric_limits<float>::max();
252 float y_min = std::numeric_limits<float>::max();
253 float y_max = -std::numeric_limits<float>::max();
254 float x_images[3] = {0};
255
256 for (int i = 0; i < 8; ++i) {
257 // Bbox from x_images
258 float x_box[3] = {x_corners[i], y_corners[i], z_corners[i]};
259 algorithm::IProjectThroughKRt(k_mat, rot_y, center_temp, x_box, x_images);
260 x_images[0] *= algorithm::IRec(x_images[2]);
261 x_images[1] *= algorithm::IRec(x_images[2]);
262 x_min = std::min(x_min, x_images[0]);
263 x_max = std::max(x_max, x_images[0]);
264 y_min = std::min(y_min, x_images[1]);
265 y_max = std::max(y_max, x_images[1]);
266 }
267
268 // Clamp bounding box from 0~boundary
269 x_min = std::min(std::max(x_min, 0.0f), x_upper_bound);
270 x_max = std::min(std::max(x_max, 0.0f), x_upper_bound);
271 y_min = std::min(std::max(y_min, 0.0f), y_upper_bound);
272 y_max = std::min(std::max(y_max, 0.0f), y_upper_bound);
273
274 // Calculate 2D center point and get cost
275 // cost = (center_gt - center_cal)**2
276 float center_cur[2] = {(x_min + x_max) / 2, (y_min + y_max) / 2};
277 float cost_cur =
278 algorithm::ISqrt(algorithm::ISqr(center_cur[0] - center_2d_target[0]) +
279 algorithm::ISqr(center_cur[1] - center_2d_target[1]));
280
281 // Stop or continue
282 if (cost_cur >= cost_pre) {
283 stop = true;
284 } else {
285 memcpy(center, center_temp, sizeof(float) * 3);
286 cost_delta = (cost_pre - cost_cur) / cost_pre;
287 cost_pre = cost_cur;
288 // Update 2D center point by descent method
289 x[0] += (center_2d_target[0] - center_cur[0]) * LEARNING_RATE;
290 x[1] += (center_2d_target[1] - center_cur[1]) * LEARNING_RATE;
291 ++iter;
292 // Termination condition
293 stop = iter >= MAX_ITERATION || cost_delta < EPS_COST_DELTA ||
294 cost_pre < K_MIN_COST;
295 }
296 }
297}
298
299// Register plugin.
301
302} // namespace camera
303} // namespace perception
304} // namespace apollo
double f
#define REGISTER_OBSTACLE_TRANSFORMER(name)
bool Init(const TransformerInitOptions &options=TransformerInitOptions()) override
Init transformer by setting parameters
bool Transform(onboard::CameraFrame *frame) override
transform 2D detections to 3D bounding box
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
bool GetProtoFromFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the file specified by the file_name as a representation of protobufs,...
Definition file.cc:132
uint32_t height
Height of point cloud
uint32_t width
Width of point cloud
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 IProjectThroughIntrinsic(const T *K, const T *X, T *x)
Definition i_util.h:111
std::shared_ptr< Object > ObjectPtr
Definition object.h:127
void GenCorners(T h, T w, T l, T *x_cor, T *y_cor, T *z_cor)
void GenRotMatrix(const T &ry, T *rot)
std::string GetConfigFile(const std::string &config_path, const std::string &config_file)
Definition util.cc:80
class register implement
Definition arena_queue.h:37
std::shared_ptr< camera::DataProvider > data_provider
#define PI