歡迎訪問我的個人Blog: zengzeyu.com
前言
官網數據集說明:http://www.cvlibs.net/datasets/kitti/raw_data.php
數據集詳細說明論文:http://www.cvlibs.net/publications/Geiger2013IJRR.pdf
KITTI的激光雷達型號爲 Velodyne HDL-64E ,具體信息如下:
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
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 中這個函數:
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 進行顯示(可選)
//
// 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;
}
以上。