autoware.universe源码略读(3.17)--perception:occupancy_grid_map_outlier_filter

news2024/11/26 1:49:49

autoware.universe源码略读3.17--perception:occupancy_grid_map_outlier_filter

  • Overview
  • (Class)RadiusSearch2dfilter
    • (Class Constructor)RadiusSearch2dfilter::RadiusSearch2dfilter
    • (mFunc)RadiusSearch2dfilter::filter
  • (Class)OccupancyGridMapOutlierFilterComponent
    • (Class Constructor)OccupancyGridMapOutlierFilterComponent::OccupancyGridMapOutlierFilterComponent
    • (mFunc)OccupancyGridMapOutlierFilterComponent::onOccupancyGridMapAndPointCloud2
    • (mFunc)OccupancyGridMapOutlierFilterComponent::filterByOccupancyGridMap
    • (Func)getCost

Overview

这个模块是根据占据栅格地图occupancy_grid_map来对点云进行滤波的,根据占用网格图的实现方式,它也可以被称为时间序列中的离群值滤波器,因为占用网格图表达的是时间序列中的占用概率。 关于这里涉及到的方法,在官方文档中有简单的介绍occupancy_grid_map_outlier_filter,甚至附上了两个YouTube上的视频,简单来说就是把点云根据occupancy grid map分成了两部分 (low occupancy probability和high occupancy probability) ,这里还有一点就是不是所有的low occupancy probability都是outliers,还会根据距离信息多一步判断

在这里插入图片描述

(Class)RadiusSearch2dfilter

看名字这个是利用半径进行2D滤波的,应该涉及到了前面提到的针对low occupancy probability的情况

(Class Constructor)RadiusSearch2dfilter::RadiusSearch2dfilter

这里面涉及到了几个参数的加载

NameTypeDescription
radius_search_2d_filter/search_radiusfloatRadius when calculating the density
radius_search_2d_filter/min_points_and_distance_ratiofloatThreshold value of the number of point clouds per radius when the distance from baselink is 1m, because the number of point clouds varies with the distance from baselink.
radius_search_2d_filter/min_pointsintMinimum number of point clouds per radius
radius_search_2d_filter/max_pointsintMaximum number of point clouds per radius

然后还实例化了一个很常用的PCL的KD树对象,应该在滤波的时候会用到

(mFunc)RadiusSearch2dfilter::filter

这个函数分成了两种参数输入方式,第一种的话输入包括了输入的点云,一个位置;然后输出的就是满足条件的点和离散点。具体的话就是找到给定位置Pose的距离满足要求的点

kd_tree_->setInputCloud(xy_cloud);
for (size_t i = 0; i < xy_cloud->points.size(); ++i) {
  const float distance =
    std::hypot(xy_cloud->points[i].x - pose.position.x, xy_cloud->points[i].y - pose.position.y);
  const int min_points_threshold = std::min(
    std::max(static_cast<int>(min_points_and_distance_ratio_ / distance + 0.5f), min_points_),
    max_points_);
  const int points_num =
    kd_tree_->radiusSearch(i, search_radius_, k_indices, k_dists, min_points_threshold);
  if (min_points_threshold <= points_num) {
    output.points.push_back(xyz_cloud.points.at(i));
  } else {
    outlier.points.push_back(xyz_cloud.points.at(i));
  }
}

第二种和第一种的方法是一样的,不过这里是直接输入了high_conf_input和low_conf_input两个点云,然后相当于给一起处理了

xy_cloud->points.resize(low_conf_xyz_cloud.points.size() + high_conf_xyz_cloud.points.size());
for (size_t i = 0; i < low_conf_xyz_cloud.points.size(); ++i) {
  xy_cloud->points[i].x = low_conf_xyz_cloud.points[i].x;
  xy_cloud->points[i].y = low_conf_xyz_cloud.points[i].y;
}
for (size_t i = low_conf_xyz_cloud.points.size(); i < xy_cloud->points.size(); ++i) {
  xy_cloud->points[i].x = high_conf_xyz_cloud.points[i - low_conf_xyz_cloud.points.size()].x;
  xy_cloud->points[i].y = high_conf_xyz_cloud.points[i - low_conf_xyz_cloud.points.size()].y;
}

(Class)OccupancyGridMapOutlierFilterComponent

本模块对应的主要节点函数

(Class Constructor)OccupancyGridMapOutlierFilterComponent::OccupancyGridMapOutlierFilterComponent

构造函数里加载了另一部分参数

NameTypeDescription
map_framestringmap frame id
base_link_framestringbase link frame id
cost_thresholdintCost threshold of occupancy grid map (0~100). 100 means 100% probability that there is an obstacle, close to 50 means that it is indistinguishable whether it is an obstacle or free space, 0 means that there is no obstacle.
enable_debuggerboolWhether to output the point cloud for debugging.
use_radius_search_2d_filterboolWhether or not to apply density-based outlier filters to objects that are judged to have low probability of occupancy on the occupancy grid map.

然后这里因为输入的点云必须和栅格地图匹配上执行后边的步骤才有意义,所以这里也是使用到了之前用到过的那种同步技巧

pointcloud_sub_.subscribe(this, "~/input/pointcloud", rmw_qos_profile_sensor_data);
occupancy_grid_map_sub_.subscribe(
  this, "~/input/occupancy_grid_map", rclcpp::QoS{1}.get_rmw_qos_profile());
sync_ptr_ = std::make_shared<Sync>(SyncPolicy(5), occupancy_grid_map_sub_, pointcloud_sub_
sync_ptr_->registerCallback(std::bind(
  &OccupancyGridMapOutlierFilterComponent::onOccupancyGridMapAndPointCloud2, this,
  std::placeholders::_1, std::placeholders::_2));

(mFunc)OccupancyGridMapOutlierFilterComponent::onOccupancyGridMapAndPointCloud2

这里滤波的过程是通过调用filterByOccupancyGridMap函数实现的

filterByOccupancyGridMap(*input_ogm, ogm_frame_pc, high_confidence_pc, low_confidence_pc);

然后根据参数配置,来决定要不要执行距离的滤波

if (radius_search_2d_filter_ptr_) {
  auto pc_frame_pose_stamped = getPoseStamped(
    *tf2_, input_ogm->header.frame_id, input_pc->header.frame_id, input_ogm->header.stamp);
  radius_search_2d_filter_ptr_->filter(
    high_confidence_pc, low_confidence_pc, pc_frame_pose_stamped.pose, filtered_low_confidence_pc,
    outlier_pc);
} else {
  outlier_pc = low_confidence_pc;
}

然后就是对要发布的点云坐标转换再发布就好了

(mFunc)OccupancyGridMapOutlierFilterComponent::filterByOccupancyGridMap

这个里面其实也很简单,就是根据阈值和对应栅格的值来判断要存进哪个里面,也没什么特殊的

for (sensor_msgs::PointCloud2ConstIterator<float> x(pointcloud, "x"), y(pointcloud, "y"),
     z(pointcloud, "z");
     x != x.end(); ++x, ++y, ++z) {
  const auto cost = getCost(occupancy_grid_map, *x, *y);
  if (cost) {
    if (cost_threshold_ < *cost) {
      high_confidence.push_back(pcl::PointXYZ(*x, *y, *z));
    } else {
      low_confidence.push_back(pcl::PointXYZ(*x, *y, *z));
    }
  } else {
    high_confidence.push_back(pcl::PointXYZ(*x, *y, *z));
  }
}

(Func)getCost

根据输入的网格和对应的xy索引,返回cost这么一个值的过程,其实主要的过程是计算xy对应的网格index,具体的cost值就是nav_msgs::msg::OccupancyGrid类型中对应的data

if (map_min_x < x && x < map_max_x && map_min_y < y && y < map_max_y) {
  unsigned int map_cell_x{};
  unsigned int map_cell_y{};
  map_cell_x = std::floor((x - map_position.x) / map_resolution);
  map_cell_y = std::floor((y - map_position.y) / map_resolution);
  size_t index = map_cell_y * map.info.width + map_cell_x;
  return map.data.at(index);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1941521.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Transformer系列总结

文章目录 1、Transformer基本原理介绍1.Transformer 结构2.嵌入表示层3. 注意力层3.1 输⼊矩阵3.2 查询矩阵和键矩阵3.3 Q和K的转置的点击除以键向量维度的平⽅根3.4 应⽤softmax函数3.5 注意力矩阵通过分数矩阵乘以值矩阵得出3.6 注意⼒矩阵 4. 前馈层5. 残差连接与层归一化6.…

虚幻引擎,体积雾、体积光、镜头泛光

1、体积雾 这里介绍的是用于地面的体积雾效果&#xff0c;效果如图1-1&#xff1a; 图1-1 首先&#xff0c;需要场景中存在指数级高度雾并开启体积雾&#xff08;如图1-2&#xff09;。然后创建材质&#xff0c;材质域选择“体积”&#xff0c;混合模式选择“Additive”。材质节…

二叉树的构造问题 | LeetCode刷题笔记 | 每日练习 | 深度优先遍历| 广度优先遍历 | Java

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f4cc;本篇分享的是与构造二叉树&#x1f384;有关的问题&#xff0c;有关二叉树的基础知识可以点击此处跳转学习&#x1f448;&#xff0c;构造二叉树的就是…

嵌入式人工智能(18-基于树莓派4B的继电器JQC-3FF-S-Z)

1、继电器 继电器是一种电控开关设备&#xff0c;由一个电磁系统和一个控制电路组成。当控制电路给予电磁系统足够的电流或电压时&#xff0c;电磁系统会产生磁场&#xff0c;使其内部的触点发生动作。这个动作可以使电流或电压在主电路中开关或转换&#xff0c;起到控制电路的…

【EarthMarker】区域级和点级遥感图像理解的视觉提示学习框架

摘要 自然图像区域视觉提示使用户可以通过各种视觉标记&#xff0c;如框、点和其他形状&#xff0c;和AI进行交互。但是&#xff0c;自然图像和RS图像之间存在显著差异&#xff0c;现有的视觉提示模型在RS场景中面临着挑战。此外&#xff0c;RS MLLMs主要关注于解释图像级RS数…

中文诗歌生成

用transformer在诗歌集上训练出的模型 import os os.environ["KERAS_BACKEND"] "tensorflow" # param ["tensorflow", "jax", "torch"] os.environ[TF_CPP_MIN_LOG_LEVEL] 2 os.environ[HF_ENDPOINT] https://hf-mirro…

拥抱AI时代:解锁Prompt技术的无限潜力与深远影响

拥抱AI时代&#xff1a;解锁Prompt技术的无限潜力与深远影响 引言 在人工智能的浩瀚星空中&#xff0c;自然语言处理&#xff08;NLP&#xff09;无疑是最耀眼的星辰之一。随着技术的不断演进&#xff0c;NLP已经从最初的简单问答系统发展成为能够生成复杂文本、理解人类情感与…

JavaScript之WebAPIs-BOM

目录 BOM操作浏览器一、Window对象1.1 BOM&#xff08;浏览器对象模型&#xff09;1.2 定时器-延时函数1.3 js执行机制1.4 location对象1.5 navigator对象1.6 history对象 二、本地存储三、补充数组中的map方法数组中的join方法数组中的forEach方法(重点)数组中的filter方法(重…

Linux_线程的同步与互斥

目录 1、互斥相关概念 2、代码体现互斥重要性 3、互斥锁 3.1 初始化锁 3.2 申请、释放锁 3.3 加锁的思想 3.4 实现加锁 3.5 锁的原子性 4、线程安全 4.1 可重入函数 4.2 死锁 5、线程同步 5.1 条件变量初始化 5.2 条件变量等待队列 5.3 唤醒等待队列…

探索 Java 中的 DeferredResult<Object>

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

(POSIX) 文件读写基础

文章目录 &#x1f5c2;️前言&#x1f4c4;ref&#x1f4c4;访问标记&#x1f5c3;️文件访问标记 &#x1f5c2;️Code&#x1f4c4;demo&#x1f4c4;分点讲解&#x1f5c3;️打开/关闭&#x1f5c3;️写&#x1f5c3;️读 &#x1f5c2;️END&#x1f31f;关注我 &#x1f…

C++ 正则库与HTTP请求

正则表达式的概念和语法 用于描述和匹配字符串的工具&#xff0c;通过特定的语法规则&#xff0c;灵活的定义复杂字符串匹配条件 常用语法总结 基本字符匹配 a&#xff1a;匹配字符aabc&#xff1a;匹配字符串abc 元字符&#xff08;特殊含义的字符&#xff09; .&#xff1a;匹…

【医学影像】RK3588+FPGA:满足远程诊疗系统8K音视频编解码及高效传输需求

医学影像 提供基于Intel平台、NXP平台、Rockchip平台的核心板、Mini-ITX主板、PICO-ITX主板以及工业整机等计算机硬件。产品板载内存&#xff0c;集成超高清编码/解码视频引擎&#xff0c;具有出色的数据处理能力和图形处理能力&#xff0c;功能高集成&#xff0c;可应用于超声…

可信推荐系统论文分享-1

《Debiasing Recommendation by Learning Identifiable Latent Confounders》

openmv学习笔记(24电赛备赛笔记)

#openmv简介 openmv一种小型&#xff0c;可编程机器视觉摄像头&#xff0c;设计应用嵌入式应用和计算边缘&#xff0c;是图传模块&#xff0c;或者认为是一种&#xff0c;具有图像处理功能的单片机&#xff0c;提供多种接口&#xff08;I2C SPI UART CAN ADC DAC &#xff0…

【BUG】已解决:Uncaught SyntaxError: Unexpected token ‘<‘

已解决&#xff1a;Could not install packages due to an EnvironmentError: [Errno 13] Permission denied 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发者社区主理人 …

如何训练出模型的推理规划能力

背景 近期opanai对AGI做了等级划分&#xff1b;等级划分意味着AGI有了一个考核定义&#xff0c;有了升级打怪的评价指标。并给出了目前openai正处在第一级&#xff0c;即将达到第二级的论断。预计在一年或者一年半内实现第二级&#xff0c;可以完成基本问题解决任务的系统。 …

抖音客户端一面

C | 字节抖音客户端一面 Http握手过程 1. 客户端问候(Client Hello) 客户端向服务器发送一个“问候”消息&#xff0c;其中包含客户端支持的SSL/TLS版本、加密算法、压缩方法以及一个随机数。 version 版本号,https也有版本号哦TLS 1.0、TLS 1.1、TLS 1.2等等 random 随机数…

【Linux】进程信号 --- 信号保存

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 如果文章对…

Linux中进程间通信--匿名管道和命名管道

本篇将会进入 Linux 进程中进程间通信&#xff0c;本篇简要的介绍了 Linux 中进程为什么需要通信&#xff0c;进程间通信的常用方式。然后详细的介绍了 Linux 进程间的管道通信方式&#xff0c;管道通信分为匿名管道和命名管道&#xff0c;本篇分别介绍了其实现的原理&#xff…