add sync input compressed; sync output could still support tp and pa
This commit is contained in:
@@ -72,8 +72,11 @@ register_keys:
|
||||
overlay_output_topic: "/odin1/combined_image/compressed"
|
||||
overlay_jpeg_quality: 85
|
||||
|
||||
# cloud_reprojection: 4th input = raw camera (sensor_msgs/Image bgr8), e.g. /odin1/image
|
||||
# cloud_reprojection 第4路图像输入;raw / compressed 二选一,由 sync_camera_compressed 控制
|
||||
# sync_camera_compressed = 0: sync_camera_topic 应该是 sensor_msgs/Image (bgr8),例如 /odin1/image
|
||||
# sync_camera_compressed = 1: sync_camera_topic 应该是 sensor_msgs/CompressedImage,例如 /odin1/image/compressed
|
||||
sync_camera_topic: "/odin1/image"
|
||||
sync_camera_compressed: 1 # sync_camera_topic would be default added /compressed
|
||||
sync_topic_prefix: "/odin1/sync"
|
||||
combined_compressed_topic: "/odin1/combined_image/compressed"
|
||||
combined_jpeg_quality: 85
|
||||
|
||||
@@ -66,6 +66,7 @@ private:
|
||||
std::string odometry_topic_;
|
||||
std::string wiwc_topic_;
|
||||
std::string camera_image_topic_;
|
||||
bool camera_image_compressed_ = false;
|
||||
std::string sync_topic_prefix_;
|
||||
std::string combined_compressed_topic_;
|
||||
int combined_jpeg_quality_;
|
||||
@@ -77,16 +78,21 @@ private:
|
||||
message_filters::Subscriber<Odometry> odom_sub_;
|
||||
message_filters::Subscriber<Odometry> wiwc_sub_;
|
||||
message_filters::Subscriber<Image> image_sub_;
|
||||
message_filters::Subscriber<CompressedImage> compressed_image_sub_;
|
||||
|
||||
typedef message_filters::sync_policies::ApproximateTime<PointCloud2, Odometry, Odometry, Image> MySyncPolicy;
|
||||
typedef message_filters::Synchronizer<MySyncPolicy> Sync;
|
||||
std::shared_ptr<Sync> sync_;
|
||||
typedef message_filters::sync_policies::ApproximateTime<PointCloud2, Odometry, Odometry, Image> RawSyncPolicy;
|
||||
typedef message_filters::Synchronizer<RawSyncPolicy> RawSync;
|
||||
typedef message_filters::sync_policies::ApproximateTime<PointCloud2, Odometry, Odometry, CompressedImage> CompressedSyncPolicy;
|
||||
typedef message_filters::Synchronizer<CompressedSyncPolicy> CompressedSync;
|
||||
std::shared_ptr<RawSync> raw_sync_;
|
||||
std::shared_ptr<CompressedSync> compressed_sync_;
|
||||
|
||||
std::string sync_cloud_topic_;
|
||||
std::string sync_cloud_slam_topic_;
|
||||
std::string sync_odom_topic_;
|
||||
std::string sync_wiwc_topic_;
|
||||
std::string sync_image_topic_;
|
||||
std::string sync_image_compressed_topic_;
|
||||
std::string sync_overlay_image_topic_;
|
||||
std::string sync_detection_debug_image_topic_;
|
||||
std::string sync_target_observation_topic_;
|
||||
@@ -98,6 +104,7 @@ private:
|
||||
rclcpp::Publisher<Odometry>::SharedPtr sync_odom_pub_;
|
||||
rclcpp::Publisher<Odometry>::SharedPtr sync_wiwc_pub_;
|
||||
rclcpp::Publisher<Image>::SharedPtr sync_image_pub_;
|
||||
rclcpp::Publisher<CompressedImage>::SharedPtr sync_image_compressed_pub_;
|
||||
|
||||
rclcpp::Publisher<CompressedImage>::SharedPtr overlay_compressed_pub_; // optional if send_overlay_
|
||||
rclcpp::Publisher<CompressedImage>::SharedPtr detection_debug_compressed_pub_; // debug detections/tracks
|
||||
@@ -114,10 +121,19 @@ private:
|
||||
#endif
|
||||
|
||||
void loadParameters();
|
||||
void syncCallback(const PointCloud2::ConstSharedPtr& cloud_msg,
|
||||
const Odometry::ConstSharedPtr& odom_msg,
|
||||
const Odometry::ConstSharedPtr& wiwc_msg,
|
||||
const Image::ConstSharedPtr& image_msg);
|
||||
void processSyncedData(const PointCloud2::ConstSharedPtr& cloud_msg,
|
||||
const Odometry::ConstSharedPtr& odom_msg,
|
||||
const Odometry::ConstSharedPtr& wiwc_msg,
|
||||
const Image& image_msg,
|
||||
const cv::Mat& cam_bgr);
|
||||
void syncCallbackRaw(const PointCloud2::ConstSharedPtr& cloud_msg,
|
||||
const Odometry::ConstSharedPtr& odom_msg,
|
||||
const Odometry::ConstSharedPtr& wiwc_msg,
|
||||
const Image::ConstSharedPtr& image_msg);
|
||||
void syncCallbackCompressed(const PointCloud2::ConstSharedPtr& cloud_msg,
|
||||
const Odometry::ConstSharedPtr& odom_msg,
|
||||
const Odometry::ConstSharedPtr& wiwc_msg,
|
||||
const CompressedImage::ConstSharedPtr& image_msg);
|
||||
};
|
||||
#else
|
||||
class CloudReprojectionRosNode
|
||||
|
||||
@@ -3,5 +3,5 @@ ros2 bag record \
|
||||
/odin1/sync/image/compressed \
|
||||
/odin1/sync/odometry \
|
||||
/odin1/sync/wiwc \
|
||||
/odin1/combined_image/compressed
|
||||
# /odin1/combined_image/compressed
|
||||
|
||||
|
||||
+129
-30
@@ -25,6 +25,7 @@ limitations under the License.
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
|
||||
#ifdef ROS2
|
||||
#include <sensor_msgs/msg/compressed_image.hpp>
|
||||
@@ -86,6 +87,22 @@ std::string format_keypoints_xyc(
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string resolve_camera_sync_topic(std::string topic, bool compressed)
|
||||
{
|
||||
const std::string suffix = "/compressed";
|
||||
if (compressed) {
|
||||
if (topic.size() < suffix.size() ||
|
||||
topic.compare(topic.size() - suffix.size(), suffix.size(), suffix) != 0) {
|
||||
topic += suffix;
|
||||
}
|
||||
} else if (
|
||||
topic.size() >= suffix.size() &&
|
||||
topic.compare(topic.size() - suffix.size(), suffix.size(), suffix) == 0) {
|
||||
topic.resize(topic.size() - suffix.size());
|
||||
}
|
||||
return topic;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#ifdef ROS2
|
||||
@@ -129,6 +146,10 @@ CloudReprojectionRosNode::CloudReprojectionRosNode(const rclcpp::NodeOptions& op
|
||||
<< "\n odometry_topic: " << odometry_topic_
|
||||
<< "\n wiwc_topic: " << wiwc_topic_
|
||||
<< "\n camera_image_topic: " << camera_image_topic_
|
||||
<< "\n camera_image_transport: " << (camera_image_compressed_ ? "compressed" : "raw")
|
||||
<< "\n sync_image_topic: " << sync_image_topic_
|
||||
<< "\n sync_image_compressed_topic: "
|
||||
<< (camera_image_compressed_ ? sync_image_compressed_topic_ : "<disabled>")
|
||||
<< "\n sync_* topics under: " << sync_topic_prefix_
|
||||
<< "\n overlay_compressed_topic: " << sync_overlay_image_topic_
|
||||
<< "\n detection_debug_topic: " << sync_detection_debug_image_topic_
|
||||
@@ -147,18 +168,39 @@ CloudReprojectionRosNode::CloudReprojectionRosNode(const rclcpp::NodeOptions& op
|
||||
cloud_sub_.subscribe(this, cloud_slam_topic_);
|
||||
odom_sub_.subscribe(this, odometry_topic_);
|
||||
wiwc_sub_.subscribe(this, wiwc_topic_);
|
||||
image_sub_.subscribe(this, camera_image_topic_);
|
||||
|
||||
sync_ = std::make_shared<Sync>(MySyncPolicy(10), cloud_sub_, odom_sub_, wiwc_sub_, image_sub_);
|
||||
sync_->registerCallback(std::bind(&CloudReprojectionRosNode::syncCallback, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
|
||||
std::placeholders::_4));
|
||||
if (camera_image_compressed_) {
|
||||
compressed_image_sub_.subscribe(this, camera_image_topic_);
|
||||
compressed_sync_ = std::make_shared<CompressedSync>(
|
||||
CompressedSyncPolicy(10), cloud_sub_, odom_sub_, wiwc_sub_, compressed_image_sub_);
|
||||
compressed_sync_->registerCallback(std::bind(
|
||||
&CloudReprojectionRosNode::syncCallbackCompressed,
|
||||
this,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
std::placeholders::_3,
|
||||
std::placeholders::_4));
|
||||
} else {
|
||||
image_sub_.subscribe(this, camera_image_topic_);
|
||||
raw_sync_ = std::make_shared<RawSync>(
|
||||
RawSyncPolicy(10), cloud_sub_, odom_sub_, wiwc_sub_, image_sub_);
|
||||
raw_sync_->registerCallback(std::bind(
|
||||
&CloudReprojectionRosNode::syncCallbackRaw,
|
||||
this,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
std::placeholders::_3,
|
||||
std::placeholders::_4));
|
||||
}
|
||||
|
||||
sync_cloud_pub_ = this->create_publisher<PointCloud2>(sync_cloud_topic_, 10);
|
||||
sync_cloud_slam_pub_ = this->create_publisher<PointCloud2>(sync_cloud_slam_topic_, 10);
|
||||
sync_odom_pub_ = this->create_publisher<Odometry>(sync_odom_topic_, 10);
|
||||
sync_wiwc_pub_ = this->create_publisher<Odometry>(sync_wiwc_topic_, 10);
|
||||
sync_image_pub_ = this->create_publisher<Image>(sync_image_topic_, 10);
|
||||
if (camera_image_compressed_) {
|
||||
sync_image_compressed_pub_ =
|
||||
this->create_publisher<CompressedImage>(sync_image_compressed_topic_, 10);
|
||||
}
|
||||
|
||||
if (send_overlay_) {
|
||||
overlay_compressed_pub_ =
|
||||
@@ -207,6 +249,7 @@ void CloudReprojectionRosNode::loadParameters()
|
||||
this->declare_parameter<std::string>("odometry_topic", "/odin1/odometry");
|
||||
this->declare_parameter<std::string>("wiwc_topic", "/odin1/wiwc");
|
||||
this->declare_parameter<std::string>("register_keys.sync_camera_topic", "/odin1/image");
|
||||
this->declare_parameter<int>("register_keys.sync_camera_compressed", 0);
|
||||
this->declare_parameter<std::string>("register_keys.sync_topic_prefix", "/odin1/sync");
|
||||
this->declare_parameter<std::string>("register_keys.combined_compressed_topic", "/odin1/combined_image/compressed");
|
||||
this->declare_parameter<int>("register_keys.combined_jpeg_quality", 85);
|
||||
@@ -244,7 +287,11 @@ void CloudReprojectionRosNode::loadParameters()
|
||||
cloud_slam_topic_ = this->get_parameter("cloud_slam_topic").as_string();
|
||||
odometry_topic_ = this->get_parameter("odometry_topic").as_string();
|
||||
wiwc_topic_ = this->get_parameter("wiwc_topic").as_string();
|
||||
camera_image_topic_ = this->get_parameter("register_keys.sync_camera_topic").as_string();
|
||||
camera_image_compressed_ =
|
||||
(this->get_parameter("register_keys.sync_camera_compressed").as_int() != 0);
|
||||
camera_image_topic_ = resolve_camera_sync_topic(
|
||||
this->get_parameter("register_keys.sync_camera_topic").as_string(),
|
||||
camera_image_compressed_);
|
||||
sync_topic_prefix_ = this->get_parameter("register_keys.sync_topic_prefix").as_string();
|
||||
combined_compressed_topic_ = this->get_parameter("register_keys.combined_compressed_topic").as_string();
|
||||
combined_jpeg_quality_ = this->get_parameter("register_keys.combined_jpeg_quality").as_int();
|
||||
@@ -260,6 +307,7 @@ void CloudReprojectionRosNode::loadParameters()
|
||||
sync_odom_topic_ = sync_topic_prefix_ + "/odometry";
|
||||
sync_wiwc_topic_ = sync_topic_prefix_ + "/wiwc";
|
||||
sync_image_topic_ = sync_topic_prefix_ + "/image";
|
||||
sync_image_compressed_topic_ = sync_topic_prefix_ + "/image/compressed";
|
||||
sync_overlay_image_topic_ = sync_topic_prefix_ + "/overlay_img/compressed";
|
||||
sync_detection_debug_image_topic_ = sync_topic_prefix_ + "/detection_img_debug/compressed";
|
||||
sync_target_observation_topic_ = sync_topic_prefix_ + "/target_observation";
|
||||
@@ -443,13 +491,14 @@ void CloudReprojectionRosNode::loadParameters()
|
||||
#endif
|
||||
}
|
||||
|
||||
void CloudReprojectionRosNode::syncCallback(
|
||||
void CloudReprojectionRosNode::processSyncedData(
|
||||
const PointCloud2::ConstSharedPtr& cloud_msg,
|
||||
const Odometry::ConstSharedPtr& odom_msg,
|
||||
const Odometry::ConstSharedPtr& wiwc_msg,
|
||||
const Image::ConstSharedPtr& image_msg)
|
||||
const Image& image_msg,
|
||||
const cv::Mat& cam_bgr)
|
||||
{
|
||||
const auto sync_stamp = image_msg->header.stamp;
|
||||
const auto sync_stamp = image_msg.header.stamp;
|
||||
|
||||
PointCloud2 sync_cloud_slam_msg = *cloud_msg;
|
||||
sync_cloud_slam_msg.header.stamp = sync_stamp;
|
||||
@@ -457,7 +506,7 @@ void CloudReprojectionRosNode::syncCallback(
|
||||
sync_odom_msg.header.stamp = sync_stamp;
|
||||
Odometry sync_wiwc_msg = *wiwc_msg;
|
||||
sync_wiwc_msg.header.stamp = sync_stamp;
|
||||
Image sync_image_msg = *image_msg;
|
||||
Image sync_image_msg = image_msg;
|
||||
sync_image_msg.header.stamp = sync_stamp;
|
||||
|
||||
|
||||
@@ -508,7 +557,7 @@ void CloudReprojectionRosNode::syncCallback(
|
||||
|
||||
PointCloud2 cloud_cam_msg;
|
||||
pcl::toROSMsg(cloud_cam, cloud_cam_msg);
|
||||
cloud_cam_msg.header = image_msg->header;
|
||||
cloud_cam_msg.header = image_msg.header;
|
||||
cloud_cam_msg.header.stamp = sync_stamp;
|
||||
if (cloud_cam_msg.header.frame_id.empty()) {
|
||||
// cloud_cam_msg.header.frame_id = cloud_msg->header.frame_id;
|
||||
@@ -525,19 +574,15 @@ void CloudReprojectionRosNode::syncCallback(
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat cam_bgr;
|
||||
if (send_overlay_ || need_combined
|
||||
const bool need_cam_bgr =
|
||||
send_overlay_ || need_combined
|
||||
#ifdef ODIN_ROS_DRIVER_HAS_TARGET_OBSERVATION
|
||||
|| enable_target_observation_
|
||||
#endif
|
||||
) {
|
||||
try {
|
||||
cv_bridge::CvImageConstPtr cv_ptr = cv_bridge::toCvShare(image_msg, "bgr8");
|
||||
cam_bgr = cv_ptr->image;
|
||||
} catch (const cv_bridge::Exception& e) {
|
||||
RCLCPP_ERROR(this->get_logger(), "cv_bridge (sync image): %s", e.what());
|
||||
return;
|
||||
}
|
||||
;
|
||||
if (need_cam_bgr && cam_bgr.empty()) {
|
||||
RCLCPP_ERROR(this->get_logger(), "Synced image decode/convert failed");
|
||||
return;
|
||||
}
|
||||
|
||||
sync_cloud_slam_pub_->publish(sync_cloud_slam_msg);
|
||||
@@ -644,8 +689,8 @@ void CloudReprojectionRosNode::syncCallback(
|
||||
*this->get_clock(),
|
||||
500,
|
||||
"Target observation | stamp=%u.%u size=%dx%d cloud=%zu detections=%d tracked=%d current_target_id=%d current_raw_id=%d selected_id=%d selected_raw_id=%d det_ind=%d reused=%s center_fallback=%s lost_comp_attempted=%s lost_comp_recovered=%s reid_attempted=%s reid_recovered=%s reid_sim=%.3f gallery=%d lost=%d bbox=%s depth=%.3f conf=%.3f depth_conf=%.3f pos_cam=%s pos_world=%s cloud_pts=%d depth_samples=%d | yolo=%.2f ms | mot=%.2f ms | depth=%.2f ms | total=%.2f ms | node_total=%.2f ms",
|
||||
image_msg->header.stamp.sec,
|
||||
image_msg->header.stamp.nanosec,
|
||||
image_msg.header.stamp.sec,
|
||||
image_msg.header.stamp.nanosec,
|
||||
cam_bgr.cols,
|
||||
cam_bgr.rows,
|
||||
cloud_cam.size(),
|
||||
@@ -688,7 +733,7 @@ void CloudReprojectionRosNode::syncCallback(
|
||||
}
|
||||
|
||||
odin_ros_driver::msg::TargetObservation observation_msg;
|
||||
observation_msg.header = image_msg->header;
|
||||
observation_msg.header = image_msg.header;
|
||||
observation_msg.header.stamp = sync_stamp;
|
||||
observation_msg.odometry = sync_odom_msg;
|
||||
observation_msg.valid = target_observation.valid;
|
||||
@@ -724,7 +769,7 @@ void CloudReprojectionRosNode::syncCallback(
|
||||
target_observation_pub_->publish(observation_msg);
|
||||
|
||||
geometry_msgs::msg::PointStamped pos_cam_msg;
|
||||
pos_cam_msg.header = image_msg->header;
|
||||
pos_cam_msg.header = image_msg.header;
|
||||
pos_cam_msg.header.stamp = sync_stamp;
|
||||
pos_cam_msg.header.frame_id = cloud_cam_msg.header.frame_id.empty()
|
||||
? "camera"
|
||||
@@ -741,7 +786,7 @@ void CloudReprojectionRosNode::syncCallback(
|
||||
target_pos_cam_pub_->publish(pos_cam_msg);
|
||||
|
||||
geometry_msgs::msg::PointStamped pos_world_msg;
|
||||
pos_world_msg.header = image_msg->header;
|
||||
pos_world_msg.header = image_msg.header;
|
||||
pos_world_msg.header.stamp = sync_stamp;
|
||||
pos_world_msg.header.frame_id = odom_msg->header.frame_id.empty()
|
||||
? "odom"
|
||||
@@ -770,7 +815,7 @@ void CloudReprojectionRosNode::syncCallback(
|
||||
return;
|
||||
}
|
||||
CompressedImage omsg;
|
||||
omsg.header = image_msg->header;
|
||||
omsg.header = image_msg.header;
|
||||
omsg.format = "jpeg";
|
||||
omsg.data.assign(obuf.begin(), obuf.end());
|
||||
overlay_compressed_pub_->publish(omsg);
|
||||
@@ -795,7 +840,7 @@ void CloudReprojectionRosNode::syncCallback(
|
||||
return;
|
||||
}
|
||||
CompressedImage dmsg;
|
||||
dmsg.header = image_msg->header;
|
||||
dmsg.header = image_msg.header;
|
||||
dmsg.format = "jpeg";
|
||||
dmsg.data.assign(dbuf.begin(), dbuf.end());
|
||||
detection_debug_compressed_pub_->publish(dmsg);
|
||||
@@ -818,13 +863,67 @@ void CloudReprojectionRosNode::syncCallback(
|
||||
}
|
||||
|
||||
CompressedImage out;
|
||||
out.header = image_msg->header;
|
||||
out.header = image_msg.header;
|
||||
out.format = "jpeg";
|
||||
out.data.assign(buf.begin(), buf.end());
|
||||
combined_pub_->publish(out);
|
||||
}
|
||||
}
|
||||
|
||||
void CloudReprojectionRosNode::syncCallbackRaw(
|
||||
const PointCloud2::ConstSharedPtr& cloud_msg,
|
||||
const Odometry::ConstSharedPtr& odom_msg,
|
||||
const Odometry::ConstSharedPtr& wiwc_msg,
|
||||
const Image::ConstSharedPtr& image_msg)
|
||||
{
|
||||
cv::Mat cam_bgr;
|
||||
const bool need_cam_bgr =
|
||||
send_overlay_ || (combined_pub_ != nullptr)
|
||||
#ifdef ODIN_ROS_DRIVER_HAS_TARGET_OBSERVATION
|
||||
|| enable_target_observation_
|
||||
#endif
|
||||
;
|
||||
if (need_cam_bgr) {
|
||||
try {
|
||||
cv_bridge::CvImageConstPtr cv_ptr = cv_bridge::toCvShare(image_msg, "bgr8");
|
||||
cam_bgr = cv_ptr->image;
|
||||
} catch (const cv_bridge::Exception& e) {
|
||||
RCLCPP_ERROR(this->get_logger(), "cv_bridge (sync image): %s", e.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
processSyncedData(cloud_msg, odom_msg, wiwc_msg, *image_msg, cam_bgr);
|
||||
}
|
||||
|
||||
void CloudReprojectionRosNode::syncCallbackCompressed(
|
||||
const PointCloud2::ConstSharedPtr& cloud_msg,
|
||||
const Odometry::ConstSharedPtr& odom_msg,
|
||||
const Odometry::ConstSharedPtr& wiwc_msg,
|
||||
const CompressedImage::ConstSharedPtr& image_msg)
|
||||
{
|
||||
if (image_msg->data.empty()) {
|
||||
RCLCPP_WARN(this->get_logger(), "Empty compressed image received");
|
||||
return;
|
||||
}
|
||||
const cv::Mat encoded(
|
||||
1,
|
||||
static_cast<int>(image_msg->data.size()),
|
||||
CV_8UC1,
|
||||
const_cast<unsigned char*>(image_msg->data.data()));
|
||||
cv::Mat cam_bgr = cv::imdecode(encoded, cv::IMREAD_COLOR);
|
||||
if (cam_bgr.empty()) {
|
||||
RCLCPP_ERROR(this->get_logger(), "cv::imdecode failed (sync compressed image)");
|
||||
return;
|
||||
}
|
||||
if (sync_image_compressed_pub_) {
|
||||
CompressedImage sync_compressed_msg = *image_msg;
|
||||
sync_image_compressed_pub_->publish(sync_compressed_msg);
|
||||
}
|
||||
auto sync_image_msg =
|
||||
cv_bridge::CvImage(image_msg->header, "bgr8", cam_bgr).toImageMsg();
|
||||
processSyncedData(cloud_msg, odom_msg, wiwc_msg, *sync_image_msg, cam_bgr);
|
||||
}
|
||||
|
||||
// ==================== ROS2 Main ====================
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user