pointcloud90度分割+球面投影(pcl+ros+python)

一.pcl+ros实现90度分割.前文有说明,略微修改,批量处理.

#include <iostream>
#include <string.h>
#include <string>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/point_types.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/conversions.h>

#include <pcl_ros/transforms.h>

#include <pcl/filters/extract_indices.h>

#include <sensor_msgs/PointCloud2.h>
#include<pcl/io/pcd_io.h>//which contains the required definitions to load and store point clouds to PCD and other file formats.
#include <pcl/io/pcd_io.h>//PCL的PCD格式文件的输入输出头文件  
#define CLIP_COR 0 //     x  zuobiao


void clip_above(double clip_cor, const pcl::PointCloud<pcl::PointXYZI>::Ptr in,
                             const pcl::PointCloud<pcl::PointXYZI>::Ptr out)
{
    pcl::ExtractIndices<pcl::PointXYZI> cliper;

    cliper.setInputCloud(in);
    pcl::PointIndices indices;
#pragma omp for
    for (size_t i = 0; i < in->points.size(); i++)
    {
        if (in->points[i].x < clip_cor)
        {
            indices.indices.push_back(i);
        }
    }
    cliper.setIndices(boost::make_shared<pcl::PointIndices>(indices));
    cliper.setNegative(true); //ture to remove the indices
    cliper.filter(*out);
}

void clip_xy(const pcl::PointCloud<pcl::PointXYZI>::Ptr in,
                             const pcl::PointCloud<pcl::PointXYZI>::Ptr out)
{
    pcl::ExtractIndices<pcl::PointXYZI> cliper;

    cliper.setInputCloud(in);
    pcl::PointIndices indices;
#pragma omp for
    for (size_t i = 0; i < in->points.size(); i++)
    {
        if (abs(in->points[i].x) < abs(in->points[i].y))
        {
            indices.indices.push_back(i);
        }
    }
    cliper.setIndices(boost::make_shared<pcl::PointIndices>(indices));
    cliper.setNegative(true); //ture to remove the indices
    cliper.filter(*out);
}


int
main (int argc, char** argv)
{
  pcl::PointCloud<pcl::PointXYZI>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZI>);
  
  // Fill in the cloud data
  pcl::PCDReader reader;
  // Replace the path below with the path where you saved your file
  int i=1;
  for( i; i < 10; i = i + 1 )
  {
      char *filename = new char[25];
      char *filename2 = new char[25];

      sprintf(filename,"%d.pcd",i);
      reader.read (filename, *cloud); // Remember to download the file first!

      std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height 
           << " data points (" << pcl::getFieldsList (*cloud) << ").";


      pcl::PointCloud<pcl::PointXYZI>::Ptr cliped_pc_ptr(new pcl::PointCloud<pcl::PointXYZI>);

      clip_above(CLIP_COR, cloud, cliped_pc_ptr);
    
      pcl::PointCloud<pcl::PointXYZI>::Ptr remove_close(new pcl::PointCloud<pcl::PointXYZI>);

      clip_xy(cliped_pc_ptr, remove_close); 

      std::cerr << "PointCloud after filtering: " << remove_close->width * remove_close->height 
           << " data points (" << pcl::getFieldsList (*remove_close) << ").";

      pcl::PCDWriter writer;
      sprintf(filename2,"%d_new.pcd",i);
      writer.write (filename2, *remove_close, false);
  }
  return (0);
}

这个程序中有两点要说明:

1.Pcd点云格式的读取

pcl::PCDReader reader

reader.read(filename,datapointcloudname)

pcl::PCDWriter writer

writer.write(filename,datapointcloud)

2.连续读取文件名称顺序增加的代码

int i=1;
  for( i; i < 10; i = i + 1 )
  {
      char *filename = new char[25];

      sprintf(filename,"%d.pcd",i);
      reader.read (filename, *cloud); // Remember to down

3.如何在利用ros完成c++的编译和运行

1)    在工作空间catkin_make,source,得到node节点.编译

2) 在文件所在文件夹中 roscore,rosrun package_name node_name.运行.




二.python 进行球面投影.


1.点云预处理

该部分来自adamshan大佬,博客地址https://blog.csdn.net/AdamShan/article/details/83544089

传统的CNN设计多用于二维的图像模式识别(宽 × 高 ×× 通道数),三维的点云数据格式不符合该模式,而且点云数据稀疏无规律,这对特征提取都是不利的,因此,在将数据输入到CNN之前,首先对数据进行球面投影,从而到一个稠密的、二维的数据,球面投影示意图如下:

在这里插入图片描述

其中,ϕ和θ 分别表示点的方位角(azimuth)和顶角(altitude),这两个角如下图所示:

在这里插入图片描述

通常来说,方位角是相对于正北方向的夹角,但是,在我们Lidar的坐标系下,方位角为相对于x方向(车辆正前方)的夹角,ϕ和θ 的计算公式为:

 

其中,(x,y,z) 为三维点云中每一个点的坐标。所以对于点云中的每一个点都可以通过其 (x,y,z)计算其(θ,ϕ) ,也就是说我们将三维空间坐标系中的点都投射到了一个球面坐标系,这个球面坐标系实则已经是一个二维坐标系了,但是,为了便于理解,我们对其角度进行微分化从而得到一个二维的直角坐标系:

 

那么,球面坐标系下的每一个点都可以使用一个直角坐标系中的点表示,如下:

在这里插入图片描述

通过这么一层变换,我们就将三维空间中任意一点的位置 (x,y,z)投射到了2维坐标系下的一个点的位置 (i,j) 我们提取点云中每一个点的5个特征: (x,y,z,intensity,range)放入对应的二维坐标 (i,j)内。从而得到一个尺寸为 (H,W,C) 张量(其中 5C=5),由于论文使用的是Kitti的64线激光雷达,所以 H=64 ,水平方向上,受Kitti数据集标注范围的限制,原论文仅使用了正前方90度的Lidar扫描,使用512个网格对它们进行了划分(即水平上采样512个点)。所以,点云数据在输入到CNN中之前,数据被预处理成了一个尺寸为 (64×512×5) 的张量。


2.代码实现

import numpy as np
import math


def pcd2npy(filename):
    m = np.empty((64, 512, 6))
    f = open(filename, 'r')
    line = f.readlines()
    for i in range(11,len(line)-1):
        a,b,c,d=line[i].split(' ',3)
        x=float(a)
        y=float(b)
        z=float(c)
        intensity=float(d)
        r = np.sqrt(x ** 2 + y ** 2 + z ** 2)  # Map Distance from sensor
        r_xy=np.sqrt(x ** 2 + y ** 2)


        theta=math.asin(z/r)* 180/math.pi
        if(theta<0):
            theta+=30

        fi=math.asin(y/r_xy)* 180/math.pi
        if(fi<0):
            fi+=90

        theta_num = theta / 0.46875
        fi_num = fi / 0.17578125

        g = math.ceil(theta_num)-1
        j = math.ceil(fi_num)-1

        m[g][j][0] = x
        m[g][j][1] = y
        m[g][j][2] = z
        m[g][j][3] = intensity
        m[g][j][4] = r
        m[g][j][5] = 0.0
        return m

k=0
for k in range(9):
    npyfile=pcd2npy("%01d"%k+"_new.pcd")
    np.save("%01d" % k + "_new.npy", npyfile)
    k+=1

1)pcd文件读取并按照4个一组划分.

2)按顺序读取文件名表达

"%01d" % k + "_new.npy"  k本身占%01d字符,所以表达应该是 1_new.npy

3)pcd文本样式查看,用open with text editor.打开如下,是从第12行开始是点云.

4)调节微分数,未完待续.

总结:

1)bin转pcd(pcl+ros)

2)点云分割(pcl+ros)

3)球面投影(python)

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值