Apollo 11.0
自动驾驶开放平台
multicue_transformer.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 <algorithm>
19#include <map>
20#include <utility>
21#include <vector>
22
23#include "cyber/common/file.h"
24#include "cyber/common/log.h"
27
28namespace apollo {
29namespace perception {
30namespace camera {
31
33 std::string config_file =
34 GetConfigFile(options.config_path, options.config_file);
35
36 if (!cyber::common::GetProtoFromFile(config_file, &multicue_param_)) {
37 AERROR << "Read config failed: " << config_file;
38 return false;
39 }
40 AINFO << multicue_param_.DebugString();
41
42 // Init object template
43 object_template_manager_ = ObjectTemplateManager::Instance();
45 mapper_.reset(new ObjMapper);
46
47 return true;
48}
49
50void MultiCueTransformer::SetObjMapperOptions(
51 base::ObjectPtr obj, const Eigen::Matrix3f &camera_k_matrix,
52 int width_image, int height_image, ObjMapperOptions *obj_mapper_options,
53 float *theta_ray) {
54 // prepare bbox2d
55 float bbox2d[4] = {
56 obj->camera_supplement.box.xmin, obj->camera_supplement.box.ymin,
57 obj->camera_supplement.box.xmax, obj->camera_supplement.box.ymax};
58 // input insanity check
59 bbox2d[0] = std::max(0.0f, bbox2d[0]);
60 bbox2d[1] = std::max(0.0f, bbox2d[1]);
61 bbox2d[2] = std::min(static_cast<float>(width_image) - 1.0f, bbox2d[2]);
62 bbox2d[3] = std::min(static_cast<float>(height_image) - 1.0f, bbox2d[3]);
63 bbox2d[2] = std::max(bbox2d[0] + 1.0f, bbox2d[2]);
64 bbox2d[3] = std::max(bbox2d[1] + 1.0f, bbox2d[3]);
65
66 // prepare dimension_hwl
67 float dimension_hwl[3] = {obj->size(2), obj->size(1), obj->size(0)};
68
69 // prepare rotation_y
70 float box_cent_x = (bbox2d[0] + bbox2d[2]) / 2;
71 Eigen::Vector3f image_point_low_center(box_cent_x, bbox2d[3], 1);
72 Eigen::Vector3f point_in_camera =
73 static_cast<Eigen::Matrix<float, 3, 1, 0, 3, 1>>(
74 camera_k_matrix.inverse() * image_point_low_center);
75 *theta_ray =
76 static_cast<float>(atan2(point_in_camera.x(), point_in_camera.z()));
77 float rotation_y =
78 *theta_ray + static_cast<float>(obj->camera_supplement.alpha);
79 base::ObjectSubType sub_type = obj->sub_type;
80
81 // enforce rotation_y to be in the range [-pi, pi)
82 const float PI = algorithm::Constant<float>::PI();
83 if (rotation_y < -PI) {
84 rotation_y += 2 * PI;
85 } else if (rotation_y >= PI) {
86 rotation_y -= 2 * PI;
87 }
88
89 memcpy(obj_mapper_options->bbox, bbox2d, sizeof(float) * 4);
90 memcpy(obj_mapper_options->hwl, dimension_hwl, sizeof(float) * 3);
91 obj_mapper_options->ry = rotation_y;
92 obj_mapper_options->is_veh = (obj->type == base::ObjectType::VEHICLE);
93 obj_mapper_options->check_dimension = multicue_param_.check_dimension();
94 obj_mapper_options->type_min_vol_index =
95 MatchTemplates(sub_type, dimension_hwl);
96
97 ADEBUG << "#2D-to-3D for one obj:";
98 ADEBUG << "Obj pred ry:" << rotation_y;
99 ADEBUG << "Obj pred type: " << static_cast<int>(sub_type);
100 ADEBUG << "Bbox: " << bbox2d[0] << ", " << bbox2d[1] << ", " << bbox2d[2]
101 << ", " << bbox2d[3];
102}
103
104int MultiCueTransformer::MatchTemplates(base::ObjectSubType sub_type,
105 float *dimension_hwl) {
106 const TemplateMap &kMinTemplateHWL =
108 const TemplateMap &kMidTemplateHWL =
110 const TemplateMap &kMaxTemplateHWL =
112
113 int type_min_vol_index = 0;
114 float min_dimension_val =
115 std::min(std::min(dimension_hwl[0], dimension_hwl[1]), dimension_hwl[2]);
116
117 const std::map<TemplateIndex, int> &kLookUpTableMinVolumeIndex =
119
120 switch (sub_type) {
122 const float *min_tmplt_cur_type = kMinTemplateHWL.at(sub_type).data();
123 const float *max_tmplt_cur_type = kMaxTemplateHWL.at(sub_type).data();
124 dimension_hwl[0] = std::min(dimension_hwl[0], max_tmplt_cur_type[0]);
125 dimension_hwl[0] = std::max(dimension_hwl[0], min_tmplt_cur_type[0]);
126 break;
127 }
131 const float *min_tmplt_cur_type = kMinTemplateHWL.at(sub_type).data();
132 const float *mid_tmplt_cur_type = kMidTemplateHWL.at(sub_type).data();
133 const float *max_tmplt_cur_type = kMaxTemplateHWL.at(sub_type).data();
134 float dh_min = fabsf(dimension_hwl[0] - min_tmplt_cur_type[0]);
135 float dh_mid = fabsf(dimension_hwl[0] - mid_tmplt_cur_type[0]);
136 float dh_max = fabsf(dimension_hwl[0] - max_tmplt_cur_type[0]);
137 std::vector<std::pair<float, float>> diff_hs;
138 diff_hs.push_back(std::make_pair(dh_min, min_tmplt_cur_type[0]));
139 diff_hs.push_back(std::make_pair(dh_mid, mid_tmplt_cur_type[0]));
140 diff_hs.push_back(std::make_pair(dh_max, max_tmplt_cur_type[0]));
141 std::sort(diff_hs.begin(), diff_hs.end(),
142 [](const std::pair<float, float> &a,
143 const std::pair<float, float> &b) -> bool {
144 return a.first < b.first;
145 });
146 dimension_hwl[0] = diff_hs[0].second;
147 break;
148 }
150 type_min_vol_index =
151 kLookUpTableMinVolumeIndex.at(TemplateIndex::CAR_MIN_VOLUME_INDEX);
152 break;
154 type_min_vol_index =
155 kLookUpTableMinVolumeIndex.at(TemplateIndex::VAN_MIN_VOLUME_INDEX);
156 break;
158 type_min_vol_index =
159 kLookUpTableMinVolumeIndex.at(TemplateIndex::TRUCK_MIN_VOLUME_INDEX);
160 break;
162 type_min_vol_index =
163 kLookUpTableMinVolumeIndex.at(TemplateIndex::BUS_MIN_VOLUME_INDEX);
164 break;
165 default:
166 if (min_dimension_val < multicue_param_.min_dimension_val()) {
167 algorithm::IScale3(dimension_hwl,
168 multicue_param_.min_dimension_val() *
169 algorithm::IRec(min_dimension_val));
170 }
171 break;
172 }
173 return type_min_vol_index;
174}
175
176void MultiCueTransformer::FillResults(float object_center[3],
177 float dimension_hwl[3], float rotation_y,
178 const Eigen::Affine3d &camera2world_pose,
179 float theta_ray, base::ObjectPtr obj) {
180 if (obj == nullptr) {
181 return;
182 }
183 object_center[1] -= dimension_hwl[0] / 2;
184 obj->camera_supplement.local_center(0) = object_center[0];
185 obj->camera_supplement.local_center(1) = object_center[1];
186 obj->camera_supplement.local_center(2) = object_center[2];
187 ADEBUG << "Obj id: " << obj->track_id;
188 ADEBUG << "Obj type: " << static_cast<int>(obj->sub_type);
189 ADEBUG << "Obj ori dimension: " << obj->size[2] << ", " << obj->size[1]
190 << ", " << obj->size[0];
191 obj->center(0) = static_cast<double>(object_center[0]);
192 obj->center(1) = static_cast<double>(object_center[1]);
193 obj->center(2) = static_cast<double>(object_center[2]);
194 obj->center = camera2world_pose * obj->center;
195
196 obj->size(2) = dimension_hwl[0];
197 obj->size(1) = dimension_hwl[1];
198 obj->size(0) = dimension_hwl[2];
199
200 Eigen::Matrix3d pos_var = mapper_->get_position_uncertainty();
201 obj->center_uncertainty(0) = static_cast<float>(pos_var(0));
202 obj->center_uncertainty(1) = static_cast<float>(pos_var(1));
203 obj->center_uncertainty(2) = static_cast<float>(pos_var(2));
204
205 float theta = rotation_y;
206 Eigen::Vector3d dir = (camera2world_pose.matrix().block(0, 0, 3, 3) *
207 Eigen::Vector3d(cos(theta), 0, -sin(theta)));
208 obj->direction[0] = static_cast<float>(dir[0]);
209 obj->direction[1] = static_cast<float>(dir[1]);
210 obj->direction[2] = static_cast<float>(dir[2]);
211 obj->theta = static_cast<float>(atan2(dir[1], dir[0]));
212 obj->theta_variance = static_cast<float>((mapper_->get_orientation_var())(0));
213
214 obj->camera_supplement.alpha = rotation_y - theta_ray;
215
216 ADEBUG << "Dimension hwl: " << dimension_hwl[0] << ", " << dimension_hwl[1]
217 << ", " << dimension_hwl[2];
218 ADEBUG << "Obj ry:" << rotation_y;
219 ADEBUG << "Obj theta: " << obj->theta;
220 ADEBUG << "Obj center from transformer: " << obj->center.transpose();
221}
222
224 if (frame->detected_objects.empty()) {
225 ADEBUG << "No object input to transformer.";
226 return true;
227 }
228
229 const auto &camera_k_matrix = frame->camera_k_matrix;
230 float k_mat[9] = {0};
231 for (size_t i = 0; i < 3; ++i) {
232 for (size_t j = 0; j < 3; ++j) {
233 k_mat[i * 3 + j] = camera_k_matrix(i, j);
234 }
235 }
236 ADEBUG << "Camera k matrix input to transformer: \n"
237 << k_mat[0] << ", " << k_mat[1] << ", " << k_mat[2] << "\n"
238 << k_mat[3] << ", " << k_mat[4] << ", " << k_mat[5] << "\n"
239 << k_mat[6] << ", " << k_mat[7] << ", " << k_mat[8] << "\n";
240
241 const int width_image = frame->data_provider->src_width();
242 const int height_image = frame->data_provider->src_height();
243 const auto &camera2world_pose = frame->camera2world_pose;
244 mapper_->Init(k_mat, width_image, height_image);
245
246 ObjMapperOptions obj_mapper_options;
247 float object_center[3] = {0};
248 float dimension_hwl[3] = {0};
249 float rotation_y = 0.0f;
250 int nr_transformed_obj = 0;
251
252 for (auto &obj : frame->detected_objects) {
253 if (obj == nullptr) {
254 ADEBUG << "Empty object input to transformer.";
255 continue;
256 }
257
258 // set object mapper options
259 float theta_ray = 0.0f;
260 SetObjMapperOptions(obj, camera_k_matrix, width_image, height_image,
261 &obj_mapper_options, &theta_ray);
262
263 // process
264 mapper_->Solve3dBbox(obj_mapper_options, object_center, dimension_hwl,
265 &rotation_y);
266
267 // fill back results
268 FillResults(object_center, dimension_hwl, rotation_y, camera2world_pose,
269 theta_ray, obj);
270
271 ++nr_transformed_obj;
272 }
273
274 return nr_transformed_obj > 0;
275}
276
277// Register plugin.
279
280} // namespace camera
281} // namespace perception
282} // namespace apollo
#define REGISTER_OBSTACLE_TRANSFORMER(name)
bool Transform(onboard::CameraFrame *frame) override
Transform 2D detections to 3D bounding box
bool Init(const TransformerInitOptions &options=TransformerInitOptions()) override
Init for ObjectTemplate and Object map
const std::map< TemplateIndex, int > & LookUpTableMinVolumeIndex()
#define ACHECK(cond)
Definition log.h:80
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
float cos(Angle16 a)
Definition angle.cc:42
float sin(Angle16 a)
Definition angle.cc:25
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
void IScale3(T x[3], T sf)
Definition i_blas.h:1868
std::shared_ptr< Object > ObjectPtr
Definition object.h:127
std::map< base::ObjectSubType, std::vector< float > > TemplateMap
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