Apollo 10.0
自动驾驶开放平台
semantic_map.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2019 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
18
19#include <utility>
20#include <vector>
21
22#include "cyber/common/file.h"
23#include "cyber/common/log.h"
24#include "cyber/task/task.h"
33
34namespace apollo {
35namespace prediction {
36
37namespace {
38
39bool ValidFeatureHistory(const ObstacleHistory& obstacle_history,
40 const double curr_base_x, const double curr_base_y) {
41 if (obstacle_history.feature_size() == 0) {
42 return false;
43 }
44
45 double center_x = curr_base_x + FLAGS_base_image_half_range;
46 double center_y = curr_base_y + FLAGS_base_image_half_range;
47
48 const Feature& feature = obstacle_history.feature(0);
49 double diff_x = feature.position().x() - center_x;
50 double diff_y = feature.position().y() - center_y;
51 double distance = std::hypot(diff_x, diff_y);
52 return distance < FLAGS_caution_distance_threshold;
53}
54
55} // namespace
56
58
60 curr_img_ = cv::Mat(2000, 2000, CV_8UC3, cv::Scalar(0, 0, 0));
61 obstacle_id_history_map_.clear();
62#ifdef __aarch64__
63 affine_transformer_.Init(cv::Size(2000, 2000), CV_8UC3);
64#endif
65}
66
68 const std::unordered_map<int, ObstacleHistory>& obstacle_id_history_map) {
69 if (obstacle_id_history_map.find(FLAGS_ego_vehicle_id) ==
70 obstacle_id_history_map.end()) {
71 return;
72 }
73
74 ego_feature_ = obstacle_id_history_map.at(FLAGS_ego_vehicle_id).feature(0);
75 if (!FLAGS_enable_async_draw_base_image) {
76 double x = ego_feature_.position().x();
77 double y = ego_feature_.position().y();
78 curr_base_x_ = x - FLAGS_base_image_half_range;
79 curr_base_y_ = y - FLAGS_base_image_half_range;
80 DrawBaseMap(x, y, curr_base_x_, curr_base_y_);
81 base_img_.copyTo(curr_img_);
82 } else {
83 base_img_.copyTo(curr_img_);
84 curr_base_x_ = base_x_;
85 curr_base_y_ = base_y_;
86 task_future_ = cyber::Async(&SemanticMap::DrawBaseMapThread, this);
87 // This is only for the first frame without base image yet
88 if (!started_drawing_) {
89 started_drawing_ = true;
90 return;
91 }
92 }
93
94 // Draw ADC trajectory
95 if (FLAGS_enable_draw_adc_trajectory) {
96 DrawADCTrajectory(cv::Scalar(0, 255, 255),
97 curr_base_x_, curr_base_y_, &curr_img_);
98 }
99
100 // Draw all obstacles_history
101 for (const auto obstacle_id_history_pair : obstacle_id_history_map) {
102 DrawHistory(obstacle_id_history_pair.second, cv::Scalar(0, 255, 255),
103 curr_base_x_, curr_base_y_, &curr_img_);
104 }
105
106 obstacle_id_history_map_ = obstacle_id_history_map;
107
108 // Crop ego_vehicle for demo
109 if (FLAGS_img_show_semantic_map) {
110 cv::Mat output_img;
111 if (GetMapById(FLAGS_ego_vehicle_id, &output_img)) {
112 cv::namedWindow("Demo window", cv::WINDOW_NORMAL);
113 cv::imshow("Demo window", output_img);
114 cv::waitKey();
115 }
116 }
117}
118
119void SemanticMap::DrawBaseMap(const double x, const double y,
120 const double base_x, const double base_y) {
121 base_img_ = cv::Mat(2000, 2000, CV_8UC3, cv::Scalar(0, 0, 0));
123 DrawRoads(center_point, base_x, base_y);
124 DrawJunctions(center_point, base_x, base_y);
125 DrawCrosswalks(center_point, base_x, base_y);
126 DrawLanes(center_point, base_x, base_y);
127}
128
129void SemanticMap::DrawBaseMapThread() {
130 std::lock_guard<std::mutex> lock(draw_base_map_thread_mutex_);
131 double x = ego_feature_.position().x();
132 double y = ego_feature_.position().y();
133 base_x_ = x - FLAGS_base_image_half_range;
134 base_y_ = y - FLAGS_base_image_half_range;
135 DrawBaseMap(x, y, base_x_, base_y_);
136}
137
138void SemanticMap::DrawRoads(const common::PointENU& center_point,
139 const double base_x, const double base_y,
140 const cv::Scalar& color) {
141 std::vector<apollo::hdmap::RoadInfoConstPtr> roads;
142 apollo::hdmap::HDMapUtil::BaseMap().GetRoads(center_point, 141.4, &roads);
143 for (const auto& road : roads) {
144 for (const auto& section : road->road().section()) {
145 std::vector<cv::Point> polygon;
146 for (const auto& edge : section.boundary().outer_polygon().edge()) {
147 if (edge.type() == 2) { // left edge
148 for (const auto& segment : edge.curve().segment()) {
149 for (const auto& point : segment.line_segment().point()) {
150 polygon.push_back(std::move(
151 GetTransPoint(point.x(), point.y(), base_x, base_y)));
152 }
153 }
154 } else if (edge.type() == 3) { // right edge
155 for (const auto& segment : edge.curve().segment()) {
156 for (const auto& point : segment.line_segment().point()) {
157 polygon.insert(polygon.begin(),
158 std::move(GetTransPoint(point.x(), point.y(),
159 base_x, base_y)));
160 }
161 }
162 }
163 }
164 cv::fillPoly(base_img_,
165 std::vector<std::vector<cv::Point>>({std::move(polygon)}),
166 color);
167 }
168 }
169}
170
171void SemanticMap::DrawJunctions(const common::PointENU& center_point,
172 const double base_x, const double base_y,
173 const cv::Scalar& color) {
174 std::vector<apollo::hdmap::JunctionInfoConstPtr> junctions;
176 &junctions);
177 for (const auto& junction : junctions) {
178 std::vector<cv::Point> polygon;
179 for (const auto& point : junction->junction().polygon().point()) {
180 polygon.push_back(
181 std::move(GetTransPoint(point.x(), point.y(), base_x, base_y)));
182 }
183 cv::fillPoly(base_img_,
184 std::vector<std::vector<cv::Point>>({std::move(polygon)}),
185 color);
186 }
187}
188
189void SemanticMap::DrawCrosswalks(const common::PointENU& center_point,
190 const double base_x, const double base_y,
191 const cv::Scalar& color) {
192 std::vector<apollo::hdmap::CrosswalkInfoConstPtr> crosswalks;
194 &crosswalks);
195 for (const auto& crosswalk : crosswalks) {
196 std::vector<cv::Point> polygon;
197 for (const auto& point : crosswalk->crosswalk().polygon().point()) {
198 polygon.push_back(
199 std::move(GetTransPoint(point.x(), point.y(), base_x, base_y)));
200 }
201 cv::fillPoly(base_img_,
202 std::vector<std::vector<cv::Point>>({std::move(polygon)}),
203 color);
204 }
205}
206
207void SemanticMap::DrawLanes(const common::PointENU& center_point,
208 const double base_x, const double base_y,
209 const cv::Scalar& color) {
210 std::vector<apollo::hdmap::LaneInfoConstPtr> lanes;
211 apollo::hdmap::HDMapUtil::BaseMap().GetLanes(center_point, 141.4, &lanes);
212 for (const auto& lane : lanes) {
213 // Draw lane_central first
214 for (const auto& segment : lane->lane().central_curve().segment()) {
215 for (int i = 0; i < segment.line_segment().point_size() - 1; ++i) {
216 const auto& p0 =
217 GetTransPoint(segment.line_segment().point(i).x(),
218 segment.line_segment().point(i).y(), base_x, base_y);
219 const auto& p1 = GetTransPoint(segment.line_segment().point(i + 1).x(),
220 segment.line_segment().point(i + 1).y(),
221 base_x, base_y);
222 double theta = atan2(segment.line_segment().point(i + 1).y() -
223 segment.line_segment().point(i).y(),
224 segment.line_segment().point(i + 1).x() -
225 segment.line_segment().point(i).x());
226 double H = theta >= 0 ? theta / (2 * M_PI) : theta / (2 * M_PI) + 1;
227 // // Original cv::cvtColor() is 4 times slower than HSVtoRGB()
228 // cv::Mat hsv(1, 1, CV_32FC3, cv::Scalar(H * 360.0, 1.0, 1.0));
229 // cv::Mat rgb;
230 // cv::cvtColor(hsv, rgb, cv::COLOR_HSV2RGB);
231 // cv::Scalar c =
232 // cv::Scalar(rgb.at<float>(0, 0) * 255, rgb.at<float>(0, 1) * 255,
233 // rgb.at<float>(0, 2) * 255);
234
235 cv::line(base_img_, p0, p1, HSVtoRGB(H), 4);
236 }
237 }
238 // Not drawing boundary for virtual city_driving lane
239 if (lane->lane().type() == 2 && lane->lane().left_boundary().virtual_() &&
240 lane->lane().right_boundary().virtual_()) {
241 continue;
242 }
243 // Draw lane's left_boundary
244 for (const auto& segment : lane->lane().left_boundary().curve().segment()) {
245 for (int i = 0; i < segment.line_segment().point_size() - 1; ++i) {
246 const auto& p0 =
247 GetTransPoint(segment.line_segment().point(i).x(),
248 segment.line_segment().point(i).y(), base_x, base_y);
249 const auto& p1 = GetTransPoint(segment.line_segment().point(i + 1).x(),
250 segment.line_segment().point(i + 1).y(),
251 base_x, base_y);
252 cv::line(base_img_, p0, p1, color, 2);
253 }
254 }
255 // Draw lane's right_boundary
256 for (const auto& segment :
257 lane->lane().right_boundary().curve().segment()) {
258 for (int i = 0; i < segment.line_segment().point_size() - 1; ++i) {
259 const auto& p0 =
260 GetTransPoint(segment.line_segment().point(i).x(),
261 segment.line_segment().point(i).y(), base_x, base_y);
262 const auto& p1 = GetTransPoint(segment.line_segment().point(i + 1).x(),
263 segment.line_segment().point(i + 1).y(),
264 base_x, base_y);
265 cv::line(base_img_, p0, p1, color, 2);
266 }
267 }
268 }
269}
270
271cv::Scalar SemanticMap::HSVtoRGB(double H, double S, double V) {
272 int I = static_cast<int>(floor(H * 6.0));
273 double F = H * 6.0 - floor(H * 6.0);
274 double M = V * (1.0 - S);
275 double N = V * (1.0 - S * F);
276 double K = V * (1.0 - S * (1.0 - F));
277 switch (I) {
278 case 0:
279 return cv::Scalar(V, K, M) * 255.0;
280 case 1:
281 return cv::Scalar(N, V, M) * 255.0;
282 case 2:
283 return cv::Scalar(M, V, K) * 255.0;
284 case 3:
285 return cv::Scalar(M, N, V) * 255.0;
286 case 4:
287 return cv::Scalar(K, M, V) * 255.0;
288 default:
289 return cv::Scalar(V, M, N) * 255.0;
290 }
291}
292
293void SemanticMap::DrawRect(const Feature& feature, const cv::Scalar& color,
294 const double base_x, const double base_y,
295 cv::Mat* img) {
296 double obs_l = feature.length();
297 double obs_w = feature.width();
298 double obs_x = feature.position().x();
299 double obs_y = feature.position().y();
300 double theta = feature.theta();
301 std::vector<cv::Point> polygon;
302 // point 1 (head-right point)
303 polygon.push_back(std::move(GetTransPoint(
304 obs_x + (cos(theta) * obs_l - sin(theta) * obs_w) / 2,
305 obs_y + (sin(theta) * obs_l + cos(theta) * obs_w) / 2, base_x, base_y)));
306 // point 2 (head-left point)
307 polygon.push_back(std::move(GetTransPoint(
308 obs_x + (cos(theta) * -obs_l - sin(theta) * obs_w) / 2,
309 obs_y + (sin(theta) * -obs_l + cos(theta) * obs_w) / 2, base_x, base_y)));
310 // point 3 (back-left point)
311 polygon.push_back(std::move(
312 GetTransPoint(obs_x + (cos(theta) * -obs_l - sin(theta) * -obs_w) / 2,
313 obs_y + (sin(theta) * -obs_l + cos(theta) * -obs_w) / 2,
314 base_x, base_y)));
315 // point 4 (back-right point)
316 polygon.push_back(std::move(GetTransPoint(
317 obs_x + (cos(theta) * obs_l - sin(theta) * -obs_w) / 2,
318 obs_y + (sin(theta) * obs_l + cos(theta) * -obs_w) / 2, base_x, base_y)));
319 cv::fillPoly(*img, std::vector<std::vector<cv::Point>>({std::move(polygon)}),
320 color);
321}
322
323void SemanticMap::DrawPoly(const Feature& feature, const cv::Scalar& color,
324 const double base_x, const double base_y,
325 cv::Mat* img) {
326 std::vector<cv::Point> polygon;
327 for (auto& polygon_point : feature.polygon_point()) {
328 polygon.push_back(std::move(
329 GetTransPoint(polygon_point.x(), polygon_point.y(), base_x, base_y)));
330 }
331 cv::fillPoly(*img, std::vector<std::vector<cv::Point>>({std::move(polygon)}),
332 color);
333}
334
335void SemanticMap::DrawHistory(const ObstacleHistory& history,
336 const cv::Scalar& color, const double base_x,
337 const double base_y, cv::Mat* img) {
338 for (int i = history.feature_size() - 1; i >= 0; --i) {
339 const Feature& feature = history.feature(i);
340 double time_decay = 1.0 - ego_feature_.timestamp() + feature.timestamp();
341 cv::Scalar decay_color = color * time_decay;
342 if (feature.id() == FLAGS_ego_vehicle_id) {
343 DrawRect(feature, decay_color, base_x, base_y, img);
344 } else {
345 if (feature.polygon_point_size() == 0) {
346 AERROR << "No polygon points in feature, please check!";
347 continue;
348 }
349 DrawPoly(feature, decay_color, base_x, base_y, img);
350 }
351 }
352}
353
354void SemanticMap::DrawADCTrajectory(const cv::Scalar& color,
355 const double base_x,
356 const double base_y,
357 cv::Mat* img) {
358 size_t traj_num = ego_feature_.adc_trajectory_point().size();
359 for (size_t i = 0; i < traj_num; ++i) {
360 double time_decay = ego_feature_.adc_trajectory_point(i).relative_time() -
361 ego_feature_.adc_trajectory_point(0).relative_time();
362 cv::Scalar decay_color = color * time_decay;
363 DrawPoly(ego_feature_, decay_color, base_x, base_y, img);
364 }
365}
366
367cv::Mat SemanticMap::CropArea(const cv::Mat& input_img,
368 const cv::Point2i& center_point,
369 const double heading) {
370 cv::Mat rotated_mat;
371#ifdef __aarch64__
372 affine_transformer_.AffineTransformsFromMat(input_img,
373 center_point, heading, 1.0, &rotated_mat);
374#else
375 cv::Mat rotation_mat =
376 cv::getRotationMatrix2D(center_point, 90.0 - heading * 180.0 / M_PI, 1.0);
377 cv::warpAffine(input_img, rotated_mat, rotation_mat, input_img.size());
378#endif
379 cv::Rect rect(center_point.x - 200, center_point.y - 300, 400, 400);
380 cv::Mat output_img;
381 cv::resize(rotated_mat(rect), output_img, cv::Size(224, 224));
382 return output_img;
383}
384
385cv::Mat SemanticMap::CropByHistory(const ObstacleHistory& history,
386 const cv::Scalar& color, const double base_x,
387 const double base_y) {
388 cv::Mat feature_map = curr_img_.clone();
389 DrawHistory(history, color, base_x, base_y, &feature_map);
390 const Feature& curr_feature = history.feature(0);
391 const cv::Point2i& center_point = GetTransPoint(
392 curr_feature.position().x(), curr_feature.position().y(), base_x, base_y);
393 return CropArea(feature_map, center_point, curr_feature.theta());
394}
395
396bool SemanticMap::GetMapById(const int obstacle_id, cv::Mat* feature_map) {
397 if (obstacle_id_history_map_.find(obstacle_id) ==
398 obstacle_id_history_map_.end()) {
399 return false;
400 }
401 const auto& obstacle_history = obstacle_id_history_map_[obstacle_id];
402
403 if (!ValidFeatureHistory(obstacle_history, curr_base_x_, curr_base_y_)) {
404 return false;
405 }
406
407 cv::Mat output_img =
408 CropByHistory(obstacle_id_history_map_[obstacle_id],
409 cv::Scalar(0, 0, 255), curr_base_x_, curr_base_y_);
410 output_img.copyTo(*feature_map);
411 return true;
412}
413
414} // namespace prediction
415} // namespace apollo
static PointENU ToPointENU(const double x, const double y, const double z=0)
static const HDMap & BaseMap()
int GetCrosswalks(const apollo::common::PointENU &point, double distance, std::vector< CrosswalkInfoConstPtr > *crosswalks) const
get all crosswalks in certain range
Definition hdmap.cc:116
int GetLanes(const apollo::common::PointENU &point, double distance, std::vector< LaneInfoConstPtr > *lanes) const
get all lanes in certain range
Definition hdmap.cc:90
int GetRoads(const apollo::common::PointENU &point, double distance, std::vector< RoadInfoConstPtr > *roads) const
get all roads in certain range
Definition hdmap.cc:144
int GetJunctions(const apollo::common::PointENU &point, double distance, std::vector< JunctionInfoConstPtr > *junctions) const
get all junctions in certain range
Definition hdmap.cc:95
void RunCurrFrame(const std::unordered_map< int, ObstacleHistory > &obstacle_id_history_map)
bool GetMapById(const int obstacle_id, cv::Mat *feature_map)
Use container manager to manage all containers
#define AERROR
Definition log.h:44
float cos(Angle16 a)
Definition angle.cc:42
float sin(Angle16 a)
Definition angle.cc:25
class register implement
Definition arena_queue.h:37
Obstacles container
Some string util functions.
repeated apollo::common::TrajectoryPoint adc_trajectory_point
optional apollo::common::Point3D position
Definition feature.proto:88