当前位置:网站首页>pcl::fromROSMsg报警告Failed to find match for field ‘intensity‘.
pcl::fromROSMsg报警告Failed to find match for field ‘intensity‘.
2022-07-04 09:32:00 【Ly.Leo】
pcl::fromROSMsg报警告Failed to find match for field 'intensity'
1 问题描述
原始点云PointCloud2类型的话题中含有intensity数据,并且在Rviz中可以将强度信息显示出来。使用pcl::fromROSMsg()函数将ROS的PointCloud2类型的消息转成pcl::PointXYZI类型的数据后,出现了Failed to find match for field ‘intensity’ 的问题1。
2 原因分析
- 发出的topic点云与接收的点云数据结构不同;
比如,发出的topic点云类型是PointXYZI(包含x, y, z, intensity),而接收的却是自定义的PointXYZIRT(包含x, y, z, intensity, ring, timestamp)
发出的点云数据结构
struct PointXYZI
{
PCL_ADD_POINT4D;
float intensity;
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
} EIGEN_ALIGN16;
接收的点云数据结构
struct PointXYZIRT
{
PCL_ADD_POINT4D;
uint8_t intensity;
uint16_t ring;
double timestamp;
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
} EIGEN_ALIGN16;
- 点云结构中数据类型不同;
其实如果只是数据结构不同还不一定能导致该问题出现,如果intensity数据类型前后一致,pcl::fromROSMsg
函数还是可以将前面一致的部分进行转换的,也就是至少x, y, z, i是可以正常被接收。但是上面的例子中PointXYZI的intensity
是float,自定义的 PointXYZIRTintensity
却是uint8_t,这样pcl::fromROSMsg
函数就会报错【参考文献】。
3 解决方案
3.1 获得topic数据结构
首先要知道所发出的数据结构中各成员的数据类型,如果提前知道,这部分可以略过。但很多情况下你或许并不知道录制时的数据结构。这里写出两个方法获得数据结构:
3.1.1 使用rviz获得
前面我们提到,rviz是可以正常显示点云的激光雷达反射率intensity的,也就是rviz可以正常接受该类型点云,可以使用rviz通过“by topic”获得选中发出的topic点云,然后从Channel Name中点击右侧下拉列表,就可以看到所有成员。但是此方法无法获得实际上的排序,但是一般排序都是XYZIRT。
3.1.2 sensor_msgs::PointCloud2数据结构获得
手册中该msg的数据结构如下,其中sensor_msgs/PointField[] fields
包含点云的数据部分。
std_msgs/Header header
uint32 height
uint32 width
sensor_msgs/PointField[] fields
bool is_bigendian
uint32 point_step
uint32 row_step
uint8[] data
bool is_dense
下面是sensor_msgs/PointField.msg的源文件,其中name
保存点云结构体的成员名称(如:x, y, z, intensity等……),offset
表示对应name
的数据在本组数据的存储位置,datatype
存储该name
的offset
是什么数据类型,但是datatype
是一个uint8的枚举,上边对各数据类型的定义的值存储对应类型。即我们将对应name
的datatype
打印出来就可以知道其类型。
# This message holds the description of one point entry in the
# PointCloud2 message format.
uint8 INT8 = 1
uint8 UINT8 = 2
uint8 INT16 = 3
uint8 UINT16 = 4
uint8 INT32 = 5
uint8 UINT32 = 6
uint8 FLOAT32 = 7
uint8 FLOAT64 = 8
string name # Name of field
uint32 offset # Offset from start of point struct
uint8 datatype # Datatype enumeration, see above
uint32 count # How many elements in the field
只要参照下面写点云的回调就可以打印出datatype
的枚举值。如打印为2,则由于uint8 UINT8 = 2
的定义,intensity应为uint8_t类型。
void MapGenerationNode::lidarCallback(const sensor_msgs::PointCloud2::ConstPtr& lidar)
{
for (int f=0; f<lidar->fields.size(); ++f)
{
if (lidar->fields[f].name == "intensity")
std::cout << "intensity lidar->fields[f].datatype = " << (int)lidar->fields[f].datatype << std::endl;
}
3.2 手动转换点云格式
自定义一个fromROSMsg_DIY的函数用于转化点云
void fromROSMsg_DIY(const sensor_msgs::PointCloud2::ConstPtr& cloud_msg,
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud)
{
// Get the field structure of this point cloud
int pointBytes = cloud_msg->point_step;
int offset_x;
int offset_y;
int offset_z;
int offset_int;
for (int f=0; f<cloud_msg->fields.size(); ++f)
{
if (cloud_msg->fields[f].name == "x")
offset_x = cloud_msg->fields[f].offset;
if (cloud_msg->fields[f].name == "y")
offset_y = cloud_msg->fields[f].offset;
if (cloud_msg->fields[f].name == "z")
offset_z = cloud_msg->fields[f].offset;
if (cloud_msg->fields[f].name == "intensity")
offset_int = cloud_msg->fields[f].offset;
}
// populate point cloud object
for (int p=0; p<cloud_msg->width*cloud_msg->height; ++p)
{
pcl::PointXYZI newPoint;
newPoint.x = *(float*)(&cloud_msg->data[0] + (pointBytes*p) + offset_x);
newPoint.y = *(float*)(&cloud_msg->data[0] + (pointBytes*p) + offset_y);
newPoint.z = *(float*)(&cloud_msg->data[0] + (pointBytes*p) + offset_z);
newPoint.intensity = *(unsigned char*)(&cloud_msg->data[0] + (pointBytes*p) + offset_int);
cloud->points.push_back(newPoint);
}
cloud->height = cloud_msg->height;
cloud->width = cloud_msg->width;
}
回调函数里面可以这么写
void MapNode::lidarCallback(const sensor_msgs::PointCloud2::ConstPtr& lidar)
{
pcl::PointCloud<pcl::PointXYZI>::Ptr lidar_cloud3(new pcl::PointCloud<pcl::PointXYZI>);
fromROSMsg_DIY(lidar, lidar_cloud3);
//...
}
也可以参考完整的一个例程【引用自这里】,但是注意该例程中没有对点云的hight和width赋值,在进行其他操作(如:pcl::io::savePCDFileASCII ()
)时可能会出问题。
#include <iostream>
#include <pcl/common/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/conversions.h>
using namespace std;
/* ---[ */
int main (int argc, char** argv)
{
if (argc < 4)
{
std::cerr << "Syntax is: " << argv[0] << " <file_in.pcd> <file_out.pcd> 0/1/2 (ascii/binary/binary_compressed) [precision (ASCII)]" << std::endl;
return (-1);
}
pcl::PCLPointCloud2 cloud_msg;
Eigen::Vector4f origin; Eigen::Quaternionf orientation;
pcl::PointCloud<pcl::PointXYZI> cloud_xyzi;
if (pcl::io::loadPCDFile (string (argv[1]), cloud_msg, origin, orientation) < 0)
{
std::cerr << "Unable to load " << argv[1] << std::endl;
return (-1);
}
// pcl::fromPCLPointCloud2(cloud,*cloud_xyzi);
int pointBytes = cloud_msg.point_step;
int offset_x;
int offset_y;
int offset_z;
int offset_int;
for (int f=0; f<cloud_msg.fields.size(); ++f)
{
if (cloud_msg.fields[f].name == "x")
offset_x = cloud_msg.fields[f].offset;
if (cloud_msg.fields[f].name == "y")
offset_y = cloud_msg.fields[f].offset;
if (cloud_msg.fields[f].name == "z")
offset_z = cloud_msg.fields[f].offset;
if (cloud_msg.fields[f].name == "intensity")
offset_int = cloud_msg.fields[f].offset;
}
std::cout << offset_x << offset_y << offset_z << offset_int << std::endl;
// populate point cloud object
for (int p=0; p<cloud_msg.width*cloud_msg.height; ++p)
{
pcl::PointXYZI newPoint;
newPoint.x = *(float*)(&cloud_msg.data[0] + (pointBytes*p) + offset_x);
newPoint.y = *(float*)(&cloud_msg.data[0] + (pointBytes*p) + offset_y);
newPoint.z = *(float*)(&cloud_msg.data[0] + (pointBytes*p) + offset_z);
newPoint.intensity = *(unsigned char*)(&cloud_msg.data[0] + (pointBytes*p) + offset_int);
//std::cout << p << " [" << newPoint.x << "," << newPoint.y << "," << newPoint.z << "," << newPoint.intensity << "]" << std::endl;
cloud_xyzi.points.push_back(newPoint);
}
cloud_xyzi.height = 1;
cloud_xyzi.width = cloud_msg.width*cloud_msg.height
int type = atoi (argv[3]);
// std::cerr << "Loaded a point cloud with " << cloud_msg.width * cloud_msg.height <<
// " points (total size is " << cloud_msg.data.size () <<
// ") and the following channels: " << pcl::getFieldsList (cloud_msg) << std::endl;
pcl::PCDWriter w;
if (type == 0)
{
std::cerr << "Saving file " << argv[2] << " as ASCII." << std::endl;
w.writeASCII (string (argv[2]), cloud_xyzi, (argc == 5) ? atoi (argv[4]) : 7);
}
else if (type == 1)
{
std::cerr << "Saving file " << argv[2] << " as binary." << std::endl;
w.writeBinary (string (argv[2]), cloud_xyzi);
}
else if (type == 2)
{
std::cerr << "Saving file " << argv[2] << " as binary_compressed." << std::endl;
w.writeBinaryCompressed (string (argv[2]), cloud_xyzi);
}
}
其CMakeLists.txt这么写
cmake_minimum_required(VERSION 2.6)
project(pcl_test)
find_package(PCL 1.8 REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable(save_pcd save_pcd2.cpp)
add_library(save_pcd_lib SHARED save_pcd.cpp)
target_link_libraries (save_pcd ${PCL_LIBRARIES})
https://blog.csdn.net/yuteng12138/article/details/124794822 ︎
边栏推荐
- Awk from entry to earth (14) awk output redirection
- Dede plug-in (multi-function integration)
- Leetcode (Sword finger offer) - 35 Replication of complex linked list
- C語言-入門-基礎-語法-[運算符,類型轉換](六)
- How do microservices aggregate API documents? This wave of show~
- C language - Introduction - Foundation - syntax - [main function, header file] (II)
- In depth investigation and Strategic Research Report on China's motion controller Market (2022 Edition)
- Reading notes on how to connect the network - hubs, routers and routers (III)
- Awk from getting started to digging in (4) user defined variables
- After unplugging the network cable, does the original TCP connection still exist?
猜你喜欢
2022-2028 global special starch industry research and trend analysis report
C language - Introduction - Foundation - syntax - data type (4)
Live in a dream, only do things you don't say
2022-2028 global industrial gasket plate heat exchanger industry research and trend analysis report
ArrayBuffer
2022-2028 global tensile strain sensor industry research and trend analysis report
[untitled] forwarding least square method
C语言-入门-基础-语法-[运算符,类型转换](六)
LeetCode 74. Search 2D matrix
AI Winter Olympics | is the future coming? Enter the entrance of the meta universe - virtual digital human
随机推荐
Awk from getting started to digging in (11) detailed explanation of awk getline function
"How to connect the Internet" reading notes - FTTH
China electronic grade sulfur trioxide Market Forecast and investment strategy report (2022 Edition)
Awk from entry to earth (18) GAW K line manual
Flutter 小技巧之 ListView 和 PageView 的各种花式嵌套
Trees and graphs (traversal)
What is inner connection and outer connection? What are the uses and benefits
Mac platform forgets the root password of MySQL
C语言-入门-基础-语法-[变量,常亮,作用域](五)
How should PMP learning ideas be realized?
The 14th five year plan and investment risk analysis report of China's hydrogen fluoride industry 2022 ~ 2028
Awk from entry to earth (14) awk output redirection
Analysis report on the development status and investment planning of China's modular power supply industry Ⓠ 2022 ~ 2028
Trim leading or trailing characters from strings- Trim leading or trailing characters from a string?
Nurse level JDEC addition, deletion, modification and inspection exercise
[on February 11, 2022, the latest and most fully available script library collection of the whole network, a total of 23]
上周热点回顾(6.27-7.3)
Research Report on the current market situation and development prospects of calcium sulfate whiskers in China (2022 Edition)
Reading notes on how to connect the network - tcp/ip connection (II)
Investment analysis and prospect prediction report of global and Chinese high purity tin oxide Market Ⓞ 2022 ~ 2027