KITTI 原始bin格式数据集转PCD格式

前言


官网数据集说明:http://www.cvlibs.net/datasets/kitti/raw_data.php
数据集详细说明论文:http://www.cvlibs.net/publications/Geiger2013IJRR.pdf
KITTI的激光雷达型号为 Velodyne HDL-64E ,具体信息如下:

1
2
3
4
5
6
7
8
9
Velodyne HDL-64E rotating 3D laser scanner
- 10 Hz
- 64 beams
- 0.09 degree angular resolution
- 2 cm distanceaccuracy
- collecting∼1.3 million points/second
- field of view: 360°
- horizontal, 26.8°
- vertical, range: 120 m

针对激光雷达点云数据集使用的信息在 KITTI_README.TXT 中有详细说明,文件下载地址:Code to use the KITTI data set with PCL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Velodyne 3D laser scan data
===========================
The velodyne point clouds are stored in the folder 'velodyne_points'. To
save space, all scans have been stored as Nx4 float matrix into a binary
file using the following code:
stream = fopen (dst_file.c_str(),"wb");
fwrite(data,sizeof(float),4*num,stream);
fclose(stream);
Here, data contains 4*num values, where the first 3 values correspond to
x,y and z, and the last value is the reflectance information. All scans
are stored row-aligned, meaning that the first 4 values correspond to the
first measurement. Since each scan might potentially have a different
number of points, this must be determined from the file size when reading
the file, where 1e6 is a good enough upper bound on the number of values:
// allocate 4 MB buffer (only ~130*4*4 KB are needed)
int32_t num = 1000000;
float *data = (float*)malloc(num*sizeof(float));
// pointers
float *px = data+0;
float *py = data+1;
float *pz = data+2;
float *pr = data+3;
// load point cloud
FILE *stream;
stream = fopen (currFilenameBinary.c_str(),"rb");
num = fread(data,sizeof(float),num,stream)/4;
for (int32_t i=0; i<num; i++) {
point_cloud.points.push_back(tPoint(*px,*py,*pz,*pr));
px+=4; py+=4; pz+=4; pr+=4;
}
fclose(stream);
x,y and y are stored in metric (m) Velodyne coordinates.

KITTI点云数据集读取与转换


官方源代码解读

Code to use the KITTI data set with PCL下载的源代码文件夹中的src/kitti2pcd.cpp 中这个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void readKittiPclBinData(std::string &in_file, std::string& out_file)
{
// load point cloud
std::fstream input(in_file.c_str(), std::ios::in | std::ios::binary);
if(!input.good()){
std::cerr << "Could not read file: " << in_file << std::endl;
exit(EXIT_FAILURE);
}
input.seekg(0, std::ios::beg);
pcl::PointCloud<pcl::PointXYZI>::Ptr points (new pcl::PointCloud<pcl::PointXYZI>);
int i;
for (i=0; input.good() && !input.eof(); i++) {
pcl::PointXYZI point;
input.read((char *) &point.x, 3*sizeof(float));
input.read((char *) &point.intensity, sizeof(float));
points->push_back(point);
}
input.close();
// g_cloud_pub.publish( points );
std::cout << "Read KTTI point cloud with " << i << " points, writing to " << out_file << std::endl;
pcl::PCDWriter writer;
// Save DoN features
writer.write< pcl::PointXYZI > (out_file, *points, false);
}

这个函数是最重要的从 KITTI 中读取 .bin 文件转 .pcd 文件。

可运行完整代码

下面贴本人完整代码,代码功能:

  • 读取文件夹下.bin 文件
  • 按照文件名进行排序(虽然默认已经排好序)
  • 转为.pcd 文件,并保存
  • 发送到 rviz 进行显示(可选)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    //
    // Created by zzy on 3/14/18.
    //
    #include <ctime>
    #include "ros/ros.h"
    #include "fcn_data_gen/ground_remove.h"
    static ros::Publisher g_cloud_pub;
    static std::vector<std::string> file_lists;
    void read_filelists(const std::string& dir_path,std::vector<std::string>& out_filelsits,std::string type)
    {
    struct dirent *ptr;
    DIR *dir;
    dir = opendir(dir_path.c_str());
    out_filelsits.clear();
    while ((ptr = readdir(dir)) != NULL){
    std::string tmp_file = ptr->d_name;
    if (tmp_file[0] == '.')continue;
    if (type.size() <= 0){
    out_filelsits.push_back(ptr->d_name);
    }else{
    if (tmp_file.size() < type.size())continue;
    std::string tmp_cut_type = tmp_file.substr(tmp_file.size() - type.size(),type.size());
    if (tmp_cut_type == type){
    out_filelsits.push_back(ptr->d_name);
    }
    }
    }
    }
    bool computePairNum(std::string pair1,std::string pair2)
    {
    return pair1 < pair2;
    }
    void sort_filelists(std::vector<std::string>& filists,std::string type)
    {
    if (filists.empty())return;
    std::sort(filists.begin(),filists.end(),computePairNum);
    }
    void readKittiPclBinData(std::string &in_file, std::string& out_file)
    {
    // load point cloud
    std::fstream input(in_file.c_str(), std::ios::in | std::ios::binary);
    if(!input.good()){
    std::cerr << "Could not read file: " << in_file << std::endl;
    exit(EXIT_FAILURE);
    }
    input.seekg(0, std::ios::beg);
    pcl::PointCloud<pcl::PointXYZI>::Ptr points (new pcl::PointCloud<pcl::PointXYZI>);
    int i;
    for (i=0; input.good() && !input.eof(); i++) {
    pcl::PointXYZI point;
    input.read((char *) &point.x, 3*sizeof(float));
    input.read((char *) &point.intensity, sizeof(float));
    points->push_back(point);
    }
    input.close();
    // g_cloud_pub.publish( points );
    std::cout << "Read KTTI point cloud with " << i << " points, writing to " << out_file << std::endl;
    pcl::PCDWriter writer;
    // Save DoN features
    writer.write< pcl::PointXYZI > (out_file, *points, false);
    }
    int main(int argc, char **argv)
    {
    // ros::init(argc, argv, "ground_remove_test");
    // ros::NodeHandle n;
    // g_cloud_pub = n.advertise< pcl::PointCloud< pcl::PointXYZI > > ("point_chatter", 1);
    std::string bin_path = "../velodyne/binary/";
    std::string pcd_path = "../velodyne/pcd/";
    read_filelists( bin_path, file_lists, "bin" );
    sort_filelists( file_lists, "bin" );
    for (int i = 0; i < file_lists.size(); ++i)
    {
    std::string bin_file = bin_path + file_lists[i];
    std::string tmp_str = file_lists[i].substr(0, file_lists[i].length() - 4) + ".pcd";
    std::string pcd_file = pcd_path + tmp_str;
    readKittiPclBinData( bin_file, pcd_file );
    }
    return 0;
    }

以上。