优化点云处理流程
This commit is contained in:
parent
45a853b86c
commit
20b6002099
@ -22,10 +22,11 @@
|
||||
using sensor_msgs::msg::PointCloud2;
|
||||
using std::placeholders::_1;
|
||||
|
||||
// 点云帧结构体
|
||||
// 点云帧结构体(新增processed_cloud存储处理后的点云)
|
||||
struct CloudFrame
|
||||
{
|
||||
std::shared_ptr<PointCloud2> cloud;
|
||||
std::shared_ptr<PointCloud2> cloud; // 原始点云
|
||||
std::shared_ptr<PointCloud2> processed_cloud; // 处理后的点云
|
||||
rclcpp::Time stamp;
|
||||
rclcpp::Time received_time; // 添加接收时间用于延时分析
|
||||
std::string source;
|
||||
@ -193,7 +194,7 @@ class LidarMerger : public rclcpp::Node
|
||||
/* ---------- 同步处理点云 ---------- */
|
||||
void processCloudSync(const PointCloud2::SharedPtr msg, const std::string& source, const rclcpp::Time& receive_time)
|
||||
{
|
||||
// 立即进行坐标变换
|
||||
// 1. 立即进行坐标变换(原始点云)
|
||||
auto transformed_cloud = transformCloud(*msg);
|
||||
if (!transformed_cloud)
|
||||
{
|
||||
@ -201,11 +202,19 @@ class LidarMerger : public rclcpp::Node
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建CloudFrame
|
||||
auto cloud_frame = std::make_shared<CloudFrame>(
|
||||
CloudFrame{transformed_cloud, rclcpp::Time(msg->header.stamp), receive_time, source});
|
||||
// 2. 对变换后的原始点云进行处理(过滤、降采样、离群点去除)
|
||||
auto processed_cloud = processSinglePointCloud(transformed_cloud);
|
||||
if (!processed_cloud)
|
||||
{
|
||||
RCLCPP_WARN(get_logger(), "Failed to process %s cloud", source.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加到缓存并立即尝试合并
|
||||
// 3. 创建CloudFrame(存储原始+处理后的点云)
|
||||
auto cloud_frame = std::make_shared<CloudFrame>(
|
||||
CloudFrame{transformed_cloud, processed_cloud, rclcpp::Time(msg->header.stamp), receive_time, source});
|
||||
|
||||
// 4. 添加到缓存并立即尝试合并
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(cache_mutex_);
|
||||
addToCache(cloud_frame);
|
||||
@ -218,6 +227,47 @@ class LidarMerger : public rclcpp::Node
|
||||
printStats();
|
||||
}
|
||||
|
||||
/* ---------- 单雷达点云处理(独立处理前后雷达点云) ---------- */
|
||||
std::shared_ptr<PointCloud2> processSinglePointCloud(const std::shared_ptr<PointCloud2>& cloud_msg)
|
||||
{
|
||||
if (!cloud_msg || cloud_msg->data.empty()) return nullptr;
|
||||
|
||||
// 将ROS点云消息转换为PCL点云
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_pcl(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
pcl::fromROSMsg(*cloud_msg, *cloud_pcl);
|
||||
|
||||
// 1. 条件过滤(含车身/主刷过滤)
|
||||
auto filtered = applyConditionalFiltering(cloud_pcl);
|
||||
if (filtered->empty())
|
||||
{
|
||||
RCLCPP_WARN(get_logger(), "[processSinglePointCloud] Filtered cloud is empty!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 2. 降采样
|
||||
auto downsampled = applyVoxelGridFiltering(filtered);
|
||||
if (downsampled->empty())
|
||||
{
|
||||
RCLCPP_WARN(get_logger(), "[processSinglePointCloud] Downsampled cloud is empty!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 3. 离群点去除
|
||||
auto outlier_removed = applyStatisticalOutlierRemoval(downsampled);
|
||||
if (outlier_removed->empty())
|
||||
{
|
||||
RCLCPP_WARN(get_logger(), "[processSinglePointCloud] Outlier-removed cloud is empty!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 转换回ROS消息
|
||||
auto processed_msg = cloud_pool_.acquire();
|
||||
pcl::toROSMsg(*outlier_removed, *processed_msg);
|
||||
processed_msg->header = cloud_msg->header;
|
||||
|
||||
return processed_msg;
|
||||
}
|
||||
|
||||
/* ---------- 添加到缓存 ---------- */
|
||||
void addToCache(std::shared_ptr<CloudFrame> frame)
|
||||
{
|
||||
@ -235,11 +285,12 @@ class LidarMerger : public rclcpp::Node
|
||||
while (cache.size() > cache_size_)
|
||||
{
|
||||
cloud_pool_.release(cache.back()->cloud);
|
||||
cloud_pool_.release(cache.back()->processed_cloud); // 释放处理后的点云
|
||||
cache.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 尝试合并 - 触发式 ---------- */
|
||||
/* ---------- 尝试合并 - 触发式(合并处理后的点云) ---------- */
|
||||
void tryMerge()
|
||||
{
|
||||
if (front_clouds_.empty() || rear_clouds_.empty()) return;
|
||||
@ -287,9 +338,9 @@ class LidarMerger : public rclcpp::Node
|
||||
return;
|
||||
}
|
||||
|
||||
// 合并点云
|
||||
// 合并处理后的点云(核心修改:不再合并原始点云)
|
||||
auto merge_start = std::chrono::high_resolution_clock::now();
|
||||
auto merged = mergeClouds(*front_frame, *rear_frame);
|
||||
auto merged = mergeProcessedClouds(*front_frame, *rear_frame);
|
||||
auto merge_end = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (!merged) return;
|
||||
@ -301,115 +352,80 @@ class LidarMerger : public rclcpp::Node
|
||||
merged->header.frame_id = target_frame_;
|
||||
|
||||
// 发布合并后的点云
|
||||
// pub_->publish(*merged);
|
||||
pub_->publish(*merged);
|
||||
merged_count_++;
|
||||
|
||||
// 将ROS点云消息转换为PCL点云
|
||||
// ========================= 栅格化 =========================
|
||||
// 将合并后的点云转换为PCL格式用于栅格化
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr merged_pcl(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
pcl::fromROSMsg(*merged, *merged_pcl);
|
||||
|
||||
// ========================= 点云 =========================
|
||||
auto processed_pcl = processPointCloud(merged_pcl);
|
||||
if (!processed_pcl) return;
|
||||
|
||||
// 将处理后的PCL点云转回ROS消息
|
||||
auto processed = std::make_shared<sensor_msgs::msg::PointCloud2>();
|
||||
pcl::toROSMsg(*processed_pcl, *processed);
|
||||
processed->header = merged->header;
|
||||
|
||||
// 发布处理后的点云
|
||||
pub_->publish(*processed);
|
||||
// ========================= 点云 =========================
|
||||
// ========================= 栅格 =========================
|
||||
auto grid = processPointCloud_grid(merged_pcl);
|
||||
if (grid.empty()) return;
|
||||
|
||||
// 可视化栅格
|
||||
if (enable_print_) visualizeGridInTerminal(grid);
|
||||
|
||||
// 发布栅格到ROS话题
|
||||
publishGrid(grid);
|
||||
// ========================= 栅格 =========================
|
||||
// 生成栅格(无需重复处理,直接基于合并后的处理点云)
|
||||
auto grid = generateOccupancyGrid(merged_pcl);
|
||||
if (!grid.empty())
|
||||
{
|
||||
// 可视化栅格
|
||||
if (enable_print_) visualizeGridInTerminal(grid);
|
||||
// 发布栅格
|
||||
publishGrid(grid);
|
||||
}
|
||||
|
||||
// 延时分析(降低频率)
|
||||
if (enable_debug_ && merged_count_ % 10 == 0) // 每10次输出一次
|
||||
{
|
||||
auto total_delay = (now_time - processed->header.stamp).seconds();
|
||||
auto total_delay = (now_time - merged->header.stamp).seconds();
|
||||
auto process_time =
|
||||
std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - merge_start).count();
|
||||
|
||||
RCLCPP_INFO(
|
||||
get_logger(),
|
||||
"Merged #%d: points=%zu → %zu, total_delay=%.3fs, process_time=%.3fms, adaptive_threshold=%.3fs",
|
||||
merged_count_, merged->data.size() / merged->point_step, processed->data.size() / processed->point_step,
|
||||
total_delay, process_time * 1000, adaptive_threshold);
|
||||
"Merged #%d: merged_points=%zu, total_delay=%.3fs, process_time=%.3fms, adaptive_threshold=%.3fs",
|
||||
merged_count_, merged->data.size() / merged->point_step, total_delay, process_time * 1000,
|
||||
adaptive_threshold);
|
||||
}
|
||||
|
||||
// 清理已使用的点云
|
||||
removeUsedClouds(front_frame, rear_frame);
|
||||
}
|
||||
|
||||
/* ---------- 点云处理流程 ---------- */
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr processPointCloud(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud)
|
||||
/* ---------- 合并处理后的点云 ---------- */
|
||||
std::shared_ptr<PointCloud2> mergeProcessedClouds(const CloudFrame& front, const CloudFrame& rear)
|
||||
{
|
||||
if (!cloud || cloud->empty()) return nullptr;
|
||||
|
||||
// 1. 条件过滤
|
||||
auto filtered = applyConditionalFiltering(cloud);
|
||||
if (filtered->empty())
|
||||
if (!front.processed_cloud || !rear.processed_cloud)
|
||||
{
|
||||
RCLCPP_WARN(get_logger(), "[processPointCloud] Filtered cloud is empty!");
|
||||
return cloud; // 返回原始云而不是nullptr
|
||||
RCLCPP_ERROR(get_logger(), "Processed cloud is null!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 2. 降采样
|
||||
auto downsampled = applyVoxelGridFiltering(filtered);
|
||||
if (downsampled->empty())
|
||||
size_t front_points = front.processed_cloud->data.size() / front.processed_cloud->point_step;
|
||||
size_t rear_points = rear.processed_cloud->data.size() / rear.processed_cloud->point_step;
|
||||
|
||||
if (front.processed_cloud->fields != rear.processed_cloud->fields ||
|
||||
front.processed_cloud->point_step != rear.processed_cloud->point_step ||
|
||||
front.processed_cloud->is_bigendian != rear.processed_cloud->is_bigendian)
|
||||
{
|
||||
RCLCPP_WARN(get_logger(), "[processPointCloud] Downsampled cloud is empty!");
|
||||
return filtered;
|
||||
RCLCPP_ERROR(get_logger(), "Processed PointCloud2 formats do not match!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 3. 离群点去除
|
||||
auto outlier_removed = applyStatisticalOutlierRemoval(downsampled);
|
||||
if (outlier_removed->empty())
|
||||
{
|
||||
RCLCPP_WARN(get_logger(), "[processPointCloud] Outlier-removed cloud is empty!");
|
||||
return downsampled;
|
||||
}
|
||||
auto merged = cloud_pool_.acquire();
|
||||
|
||||
return outlier_removed;
|
||||
}
|
||||
std::vector<std::vector<int>> processPointCloud_grid(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud)
|
||||
{
|
||||
if (!cloud || cloud->empty()) return {}; // 返回空栅格
|
||||
// 复制元数据
|
||||
merged->header = front.processed_cloud->header;
|
||||
merged->fields = front.processed_cloud->fields;
|
||||
merged->is_bigendian = front.processed_cloud->is_bigendian;
|
||||
merged->point_step = front.processed_cloud->point_step;
|
||||
merged->height = 1;
|
||||
merged->width = front_points + rear_points;
|
||||
|
||||
// 1. 条件过滤
|
||||
auto filtered = applyConditionalFiltering(cloud);
|
||||
if (filtered->empty())
|
||||
{
|
||||
RCLCPP_WARN(get_logger(), "[processPointCloud_grid] Filtered cloud is empty!");
|
||||
return {};
|
||||
}
|
||||
// 高效合并处理后的点云数据
|
||||
merged->data.clear();
|
||||
merged->data.reserve(front.processed_cloud->data.size() + rear.processed_cloud->data.size());
|
||||
merged->data.insert(merged->data.end(), front.processed_cloud->data.begin(), front.processed_cloud->data.end());
|
||||
merged->data.insert(merged->data.end(), rear.processed_cloud->data.begin(), rear.processed_cloud->data.end());
|
||||
merged->row_step = merged->data.size();
|
||||
|
||||
// 2. 降采样
|
||||
auto downsampled = applyVoxelGridFiltering(filtered);
|
||||
if (downsampled->empty())
|
||||
{
|
||||
RCLCPP_WARN(get_logger(), "[processPointCloud_grid] Downsampled cloud is empty!");
|
||||
return {};
|
||||
}
|
||||
|
||||
// 3. 离群点去除
|
||||
auto outlier_removed = applyStatisticalOutlierRemoval(downsampled);
|
||||
if (outlier_removed->empty())
|
||||
{
|
||||
RCLCPP_WARN(get_logger(), "[processPointCloud_grid] Outlier-removed cloud is empty!");
|
||||
return {};
|
||||
}
|
||||
|
||||
// 4. 栅格化处理并返回栅格结果
|
||||
return generateOccupancyGrid(outlier_removed);
|
||||
return merged;
|
||||
}
|
||||
|
||||
/* ---------- 条件过滤 ---------- */
|
||||
@ -433,7 +449,6 @@ class LidarMerger : public rclcpp::Node
|
||||
|
||||
// 不启用车身过滤,直接返回
|
||||
if (!filter_car_) return filtered;
|
||||
// RCLCPP_INFO(get_logger(), "启用车身过滤");
|
||||
|
||||
// 使用CropBox移除车身区域
|
||||
pcl::CropBox<pcl::PointXYZ> crop;
|
||||
@ -453,8 +468,6 @@ class LidarMerger : public rclcpp::Node
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr output(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
crop.filter(*output);
|
||||
|
||||
// return output;
|
||||
|
||||
// 右侧主刷 (x:0.85~1.25, y:0.6~0.96, z:1.2~1.65)
|
||||
pcl::CropBox<pcl::PointXYZ> crop1;
|
||||
crop1.setInputCloud(output);
|
||||
@ -630,6 +643,7 @@ class LidarMerger : public rclcpp::Node
|
||||
// 发布消息
|
||||
grid_pub_->publish(msg);
|
||||
}
|
||||
|
||||
/* ---------- 优化的匹配算法 ---------- */
|
||||
std::pair<std::shared_ptr<CloudFrame>, std::shared_ptr<CloudFrame>> findBestMatchOptimized()
|
||||
{
|
||||
@ -685,6 +699,7 @@ class LidarMerger : public rclcpp::Node
|
||||
if (front_it != front_clouds_.end())
|
||||
{
|
||||
cloud_pool_.release((*front_it)->cloud);
|
||||
cloud_pool_.release((*front_it)->processed_cloud);
|
||||
front_clouds_.erase(front_it);
|
||||
}
|
||||
|
||||
@ -693,6 +708,7 @@ class LidarMerger : public rclcpp::Node
|
||||
if (rear_it != rear_clouds_.end())
|
||||
{
|
||||
cloud_pool_.release((*rear_it)->cloud);
|
||||
cloud_pool_.release((*rear_it)->processed_cloud);
|
||||
rear_clouds_.erase(rear_it);
|
||||
}
|
||||
|
||||
@ -717,6 +733,7 @@ class LidarMerger : public rclcpp::Node
|
||||
RCLCPP_DEBUG(get_logger(), "Cleaning up old front cloud, age=%.3fs", age);
|
||||
}
|
||||
cloud_pool_.release(front_clouds_.back()->cloud);
|
||||
cloud_pool_.release(front_clouds_.back()->processed_cloud);
|
||||
front_clouds_.pop_back();
|
||||
}
|
||||
else
|
||||
@ -736,6 +753,7 @@ class LidarMerger : public rclcpp::Node
|
||||
RCLCPP_DEBUG(get_logger(), "Cleaning up old rear cloud, age=%.3fs", age);
|
||||
}
|
||||
cloud_pool_.release(rear_clouds_.back()->cloud);
|
||||
cloud_pool_.release(rear_clouds_.back()->processed_cloud);
|
||||
rear_clouds_.pop_back();
|
||||
}
|
||||
else
|
||||
@ -745,39 +763,6 @@ class LidarMerger : public rclcpp::Node
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 合并点云 ---------- */
|
||||
std::shared_ptr<PointCloud2> mergeClouds(const CloudFrame& front, const CloudFrame& rear)
|
||||
{
|
||||
size_t front_points = front.cloud->data.size() / front.cloud->point_step;
|
||||
size_t rear_points = rear.cloud->data.size() / rear.cloud->point_step;
|
||||
|
||||
if (front.cloud->fields != rear.cloud->fields || front.cloud->point_step != rear.cloud->point_step ||
|
||||
front.cloud->is_bigendian != rear.cloud->is_bigendian)
|
||||
{
|
||||
RCLCPP_ERROR(get_logger(), "PointCloud2 formats do not match!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto merged = cloud_pool_.acquire();
|
||||
|
||||
// 复制元数据
|
||||
merged->header = front.cloud->header;
|
||||
merged->fields = front.cloud->fields;
|
||||
merged->is_bigendian = front.cloud->is_bigendian;
|
||||
merged->point_step = front.cloud->point_step;
|
||||
merged->height = 1;
|
||||
merged->width = front_points + rear_points;
|
||||
|
||||
// 高效合并数据
|
||||
merged->data.clear();
|
||||
merged->data.reserve(front.cloud->data.size() + rear.cloud->data.size());
|
||||
merged->data.insert(merged->data.end(), front.cloud->data.begin(), front.cloud->data.end());
|
||||
merged->data.insert(merged->data.end(), rear.cloud->data.begin(), rear.cloud->data.end());
|
||||
merged->row_step = merged->data.size();
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
/* ---------- 坐标变换 - 简化版 ---------- */
|
||||
std::shared_ptr<PointCloud2> transformCloud(const PointCloud2& in)
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user