欢迎点云相关产学研的学者和团体加入我们。
本小节中我们学习如何连接两个不同点云为一个点云,进行连接操作前要确保两个数据集中字段的类型相同和维度相等。同时也学习如何连接两个不同点云的字段(例如,颜色、法线),这种操作的强制约束条件是两个数据集中点的数目必须一样,例如,点云A是N个点的xyz点,点云B是N个点的rgb点,则连接两个字段形成点云C是N个点xyzrgb类型。
首先,在PCL(Point Cloud Learning)中国协助发行的书[1]提供光盘的第4章例3文件夹中,打开名为concatenate_clouds.cpp的代码文件。
现在,解析上面的打开的源代码,在下面几行中:
pcl::PointCloud<pcl::PointXYZ> cloud_a,cloud_b,cloud_c;
pcl::PointCloud<pcl::Normal> n_cloud_b; //存储进行连接时需要的normal点云
pcl::PointCloud<pcl::PointNormal> p_n_cloud_c;//存储连接xyz与normal后的点云
// 创建点云数据
cloud_a.width=3; //设置cloud_a点个数为3,
cloud_a.height=cloud_b.height=n_cloud_b.height=1;//设置都为无序点云
cloud_a.points.resize(cloud_a.width*cloud_a.height);
if(strcmp(argv[1],"-p")==0) //判断进行是否为连接a+b=c
{
cloud_b.width=2;
cloud_b.points.resize(cloud_b.width*cloud_b.height);
}
else{
n_cloud_b.width=3; //如果是连接xyz与normal则生成3个法线
n_cloud_b.points.resize(n_cloud_b.width*n_cloud_b.height);
}
//以下循环生成无序点云,填充上面定义的两种类型点云对象
for(size_t i=0;i<cloud_a.points.size();++i)
{ //cloud_a始终产生3个点
cloud_a.points[i].x=1024*rand()/(RAND_MAX+1.0f);
cloud_a.points[i].y=1024*rand()/(RAND_MAX+1.0f);
cloud_a.points[i].z=1024*rand()/(RAND_MAX+1.0f);
}
if(strcmp(argv[1],"-p")==0)
for(size_t i=0;i<cloud_b.points.size();++i)
{//如果连接a+b=c则cloud_b用2个点作为xyz数据
cloud_b.points[i].x=1024*rand()/(RAND_MAX+1.0f);
cloud_b.points[i].y=1024*rand()/(RAND_MAX+1.0f);
cloud_b.points[i].z=1024*rand()/(RAND_MAX+1.0f);
}
else
for(size_t i=0;i<n_cloud_b.points.size();++i)
{//如果连接xyz+normal=xyznormal则n_cloud_b用3个点作为normal数据
n_cloud_b.points[i].normal[0]=1024*rand()/(RAND_MAX+1.0f);
n_cloud_b.points[i].normal[1]=1024*rand()/(RAND_MAX+1.0f);
n_cloud_b.points[i].normal[2]=1024*rand()/(RAND_MAX+1.0f);
}
我们定义了连接点云会用到的五个点云对象:三个输入(cloud_a、cloud_b和n_cloud_b),两个输出(cloud_c和p_n_cloud_c)。然后我们为两个输入点云(cloud_a和cloud_b或者cloud_a和n_cloud_b)填充数据。
然后,下面几行:
std::cerr<<"Cloud A: "<<std::endl;
for(size_t i=0;i<cloud_a.points.size();++i)
std::cerr<<" "<<cloud_a.points[i].x<<" "<<cloud_a.points[i].y<<" "<<cloud_a.points[i].z<<std::endl;
std::cerr<<"Cloud B: "<<std::endl;
if(strcmp(argv[1],"-p")==0)
for(size_t i=0;i<cloud_b.points.size();++i)
std::cerr<<" "<<cloud_b.points[i].x<<" "<<cloud_b.points[i].y<<" "<<cloud_b.points[i].z<<std::endl;
else
for(size_t i=0;i<n_cloud_b.points.size();++i)
std::cerr<<" "<<n_cloud_b.points[i].normal[0]<<" "<<n_cloud_b.points[i].normal[1]<<" "<<n_cloud_b.points[i].normal[2]<<std::endl;
把cloud_a和cloud_b或n_cloud_b(取决于命令行参数)的数据打印在标准输出上。如果我们需要连接点云,那么下面的代码:
cloud_c=cloud_a;
cloud_c+=cloud_b;
把cloud_a和cloud_b连接在一起创建了cloud_c。
另外如果要连接字段,那么下面的代码:
pcl::concatenateFields(cloud_a,n_cloud_b,p_n_cloud_c);
通过把cloud_a和n_cloud_b字段连接在一起创建了p_n_cloud_c。最后:
std::cerr<<"Cloud C: "<<std::endl;
for(size_t i=0;i<cloud_c.points.size();++i)
std::cerr<<" "<<cloud_c.points[i].x<<" "<<cloud_c.points[i].y<<" "<<cloud_c.points[i].z<<" "<<std::endl;
或者
std::cerr<<"Cloud C: "<<std::endl;
for(size_t i=0;i<p_n_cloud_c.points.size();++i)
std::cerr<<" "<<
p_n_cloud_c.points[i].x<<" "<<p_n_cloud_c.points[i].y<<" "<<p_n_cloud_c.points[i].z<<" "<<
p_n_cloud_c.points[i].normal[0]<<" "<<p_n_cloud_c.points[i].normal[1]<<" "<<p_n_cloud_c.points[i].normal[2]<<std::endl;
上面两段代码中的一段用来把cloud_c或者p_n_cloud_c的内容显示在屏幕上,这取决于我们连接是点云还是字段。
利用光盘提供的CMakeLists.txt文件,在cmake中建立工程文件,并生成相应的可执行文件,生成可执行程序之后,就可以运行了。在cmd中键入以下命令来连接点,
...>concatenate_clouds.exe -p
或者键入以下命令来连接字段。
...>concatenate_clouds.exe -f
运行程序结果如图1所示,先是点云字段间连接,后面是点云连接。
图1 点云连接例子运行结果
敬请关注PCL(Point Cloud Learning)中国更多的点云库PCL(Point Cloud Library)相关官方教程。
参考文献:
1.朱德海、郭浩、苏伟.点云库PCL学习教程(ISBN 978-7-5124-0954-5)北京航空航天出版社 2012-10