23#include "opencv2/opencv.hpp"
25#include "modules/common_msgs/basic_msgs/geometry.pb.h"
26#include "modules/common_msgs/perception_msgs/perception_obstacle.pb.h"
27#include "modules/dreamview/proto/camera_update.pb.h"
41void ConvertMatrixToArray(
const Eigen::Matrix4d &matrix,
42 std::vector<double> *array) {
43 const double *pointer = matrix.data();
44 for (
int i = 0; i < matrix.size(); ++i) {
45 array->push_back(pointer[i]);
49template <
typename Po
int>
50void ConstructTransformationMatrix(
const Quaternion &quaternion,
51 const Point &translation,
52 Eigen::Matrix4d *matrix) {
53 matrix->setConstant(0);
55 q.x() = quaternion.qx();
56 q.
y() = quaternion.qy();
57 q.
z() = quaternion.qz();
58 q.
w() = quaternion.qw();
59 matrix->block<3, 3>(0, 0) = q.normalized().toRotationMatrix();
60 (*matrix)(0, 3) = translation.
x();
61 (*matrix)(1, 3) = translation.y();
62 (*matrix)(2, 3) = translation.z();
68 : websocket_(websocket),
69 node_(cyber::
CreateNode(
"perception_camera_updater")) {
73void PerceptionCameraUpdater::StartStream(
const double &time_interval_ms,
74 const std::string &channel_name,
75 nlohmann::json *subscribe_param) {
76 if (channel_name.empty()) {
77 AERROR <<
"Failed to subscribe channel for channel is empty!";
80 if (std::find(channels_.begin(), channels_.end(), channel_name) ==
82 AERROR <<
"Failed to subscribe channel: " << channel_name
83 <<
" for channels_ not registered!";
86 if (time_interval_ms > 0) {
91 [channel_name,
this]() { this->OnTimer(channel_name); },
false));
94 this->OnTimer(channel_name);
99 const std::string &channel_name) {
100 std::lock_guard<std::mutex> lck(channel_updater_map_mutex_);
101 if (channel_updaters_.find(channel_name) == channel_updaters_.end()) {
103 channel_updaters_[channel_name]->perception_camera_reader_ =
106 [channel_name,
this](
const std::shared_ptr<drivers::Image> &image) {
107 OnImage(image, channel_name);
110 channel_updaters_[channel_name]->perception_obstacle_reader_ =
111 GetObstacleReader(channel_name);
113 return channel_updaters_[channel_name];
116void PerceptionCameraUpdater::Stop() {
117 channel_updaters_.clear();
120void PerceptionCameraUpdater::StopStream(
const std::string &channel_name) {
121 if (channel_name.empty()) {
122 AERROR <<
"Failed to unsubscribe channel for channel is empty!";
138void PerceptionCameraUpdater::OnTimer(
const std::string &channel_name) {
139 PublishMessage(channel_name);
142void PerceptionCameraUpdater::PublishMessage(
const std::string &channel_name) {
145 if (!channel_updaters_[channel_name]
146 ->perception_camera_reader_->HasWriter()) {
153 GetUpdate(&to_send, channel_name);
155 StreamData stream_data;
156 std::string stream_data_string;
157 stream_data.set_action(
"stream");
158 stream_data.set_data_name(
"camera");
159 stream_data.set_channel_name(channel_name);
160 std::vector<uint8_t> byte_data(to_send.begin(), to_send.end());
161 stream_data.set_data(&(byte_data[0]), byte_data.size());
162 stream_data.set_type(
"camera");
163 stream_data.SerializeToString(&stream_data_string);
164 websocket_->BroadcastBinaryData(stream_data_string);
167void PerceptionCameraUpdater::GetImageLocalization(
168 std::vector<double> *localization,
const std::string &channel_name) {
177 double timestamp_diff = std::numeric_limits<double>::max();
180 const double tmp_diff =
184 timestamp_diff = tmp_diff;
194 if (tmp_diff < std::fabs(timestamp_diff)) {
201 Eigen::Matrix4d localization_matrix;
202 ConstructTransformationMatrix(image_pos.orientation(), image_pos.position(),
203 &localization_matrix);
204 ConvertMatrixToArray(localization_matrix, localization);
207bool PerceptionCameraUpdater::QueryStaticTF(
const std::string &frame_id,
208 const std::string &child_frame_id,
209 Eigen::Matrix4d *matrix) {
210 TransformStamped transform;
211 if (tf_buffer_->GetLatestStaticTF(frame_id, child_frame_id, &transform)) {
212 ConstructTransformationMatrix(transform.transform().rotation(),
213 transform.transform().translation(), matrix);
219void PerceptionCameraUpdater::GetLocalization2CameraTF(
220 std::vector<double> *localization2camera_tf) {
221 Eigen::Matrix4d localization2camera_mat = Eigen::Matrix4d::Identity();
227 Eigen::Matrix4d loc2novatel_mat;
228 if (QueryStaticTF(
"localization",
"novatel", &loc2novatel_mat)) {
229 localization2camera_mat *= loc2novatel_mat;
232 Eigen::Matrix4d novatel2lidar_mat;
233 if (QueryStaticTF(
"novatel",
"velodyne128", &novatel2lidar_mat)) {
234 localization2camera_mat *= novatel2lidar_mat;
237 Eigen::Matrix4d lidar2camera_mat;
238 if (QueryStaticTF(
"velodyne128",
"front_6mm", &lidar2camera_mat)) {
239 localization2camera_mat *= lidar2camera_mat;
242 ConvertMatrixToArray(localization2camera_mat, localization2camera_tf);
286void PerceptionCameraUpdater::OnImage(
287 const std::shared_ptr<apollo::drivers::Image> &image,
288 const std::string& channel_name) {
289 CameraChannelUpdater* updater = GetCameraChannelUpdater(channel_name);
290 if (!updater->enabled_) {
293 cv::Mat mat(image->height(), image->width(), CV_8UC3,
294 const_cast<char *
>(image->data().data()), image->step());
295 cv::cvtColor(mat, mat, cv::COLOR_RGB2BGR);
297 cv::Size(
static_cast<int>(image->width() * kImageScale),
298 static_cast<int>(image->height() * kImageScale)),
299 0, 0, cv::INTER_LINEAR);
300 cv::imencode(
".jpg", mat, updater->image_buffer_, std::vector<int>());
301 double next_image_timestamp;
302 if (image->has_measurement_time()) {
303 next_image_timestamp = image->measurement_time();
305 next_image_timestamp = image->header().timestamp_sec();
307 std::lock_guard<std::mutex> lock(updater->image_mutex_);
308 if (next_image_timestamp < updater->current_image_timestamp_) {
309 updater->localization_queue_.clear();
311 updater->current_image_timestamp_ = next_image_timestamp;
312 updater->camera_update_.set_image(&(updater->image_buffer_[0]),
313 updater->image_buffer_.size());
314 updater->camera_update_.set_k_image_scale(kImageScale);
317void PerceptionCameraUpdater::OnLocalization(
318 const std::shared_ptr<LocalizationEstimate> &localization) {
319 for (
auto iter = channel_updaters_.begin(); iter != channel_updaters_.end();
321 if (iter->second->enabled_) {
322 std::lock_guard<std::mutex> lock(iter->second->localization_mutex_);
323 iter->second->localization_queue_.push_back(localization);
328void PerceptionCameraUpdater::OnObstacles(
329 const std::shared_ptr<apollo::perception::PerceptionObstacles> &obstacles,
330 const std::string &channel_name) {
331 CameraChannelUpdater *updater = GetCameraChannelUpdater(channel_name);
332 perception_obstacle_enable_ =
true;
333 std::lock_guard<std::mutex> lock(updater->obstacle_mutex_);
334 updater->bbox2ds.clear();
335 updater->obstacle_id.clear();
336 updater->obstacle_sub_type.clear();
337 for (
const auto &obstacle : obstacles->perception_obstacle()) {
338 updater->bbox2ds.push_back(obstacle.bbox2d());
339 updater->obstacle_id.push_back(obstacle.id());
340 updater->obstacle_sub_type.push_back(obstacle.sub_type());
344void PerceptionCameraUpdater::InitReaders() {
345 node_->CreateReader<LocalizationEstimate>(
346 FLAGS_localization_topic,
347 [
this](
const std::shared_ptr<LocalizationEstimate> &localization) {
348 OnLocalization(localization);
352void PerceptionCameraUpdater::GetUpdate(std::string *camera_update,
353 const std::string &channel_name) {
355 std::vector<double> localization;
356 GetImageLocalization(&localization, channel_name);
360 std::lock_guard<std::mutex> lock1(updater->
image_mutex_, std::adopt_lock);
365 *(updater->
camera_update_).mutable_localization() = {localization.begin(),
367 std::vector<double> localization2camera_tf;
368 GetLocalization2CameraTF(&localization2camera_tf);
370 localization2camera_tf.begin(), localization2camera_tf.end()};
373 if (perception_obstacle_enable_) {
384void PerceptionCameraUpdater::GetChannelMsg(
385 std::vector<std::string> *channels) {
386 GetChannelMsgWithFilter(channels,
"drivers.Image",
"/raw/image",
true);
389std::shared_ptr<cyber::Reader<apollo::perception::PerceptionObstacles>>
390PerceptionCameraUpdater::GetObstacleReader(
const std::string &channel_name) {
394 size_t camera_string_end_pos = channel_name.find_last_of(
"/");
395 size_t camera_string_start_pos =
396 channel_name.find_last_of(
"/", camera_string_end_pos - 1);
397 std::string camera_name =
398 channel_name.substr(camera_string_start_pos + 1,
399 camera_string_end_pos - camera_string_start_pos - 1);
400 std::string perception_obstacle_channel =
401 "/apollo/prediction/perception_obstacles_" + camera_name;
402 auto channel_manager =
403 apollo::cyber::service_discovery::TopologyManager::Instance()
405 std::shared_ptr<cyber::Reader<apollo::perception::PerceptionObstacles>>
406 perception_obstacle_reader;
408 if (!channel_manager->HasWriter(perception_obstacle_channel)) {
409 perception_obstacle_reader =
411 FLAGS_perception_obstacle_topic,
412 [channel_name,
this](
413 const std::shared_ptr<apollo::perception::PerceptionObstacles>
414 &obstacles) { OnObstacles(obstacles, channel_name); });
417 perception_obstacle_reader =
419 perception_obstacle_channel,
420 [channel_name,
this](
421 const std::shared_ptr<apollo::perception::PerceptionObstacles>
422 &obstacles) { OnObstacles(obstacles, channel_name); });
424 return perception_obstacle_reader;
Used to perform oneshot or periodic timing tasks
PerceptionCameraUpdater(WebSocketHandler *websocket)
std::unique_ptr< Node > CreateNode(const std::string &node_name, const std::string &name_space)
std::vector< apollo::perception::BBox2D > bbox2ds
CameraUpdate camera_update_
std::vector< uint8_t > image_buffer_
std::mutex localization_mutex_
std::deque< std::shared_ptr< apollo::localization::LocalizationEstimate > > localization_queue_
std::vector< int32_t > obstacle_sub_type
std::unique_ptr< cyber::Timer > timer_
std::mutex obstacle_mutex_
std::vector< int32_t > obstacle_id
double current_image_timestamp_