承接上一篇文章《使用深度学习进行点云匹配(三)》。因为之前提到过因为硬件原因我自己无法去训练3Dmatch描述子,因此接下来我的任务是尝试应用这个模型。我更换了原来的点云数据,新数据来自于斯坦福大学的3D扫描数据库,网址为;http://graphics.stanford.edu/data/3Dscanrep/,我使用了其中赫赫有名的兔子模型。
点击蓝字进行下载,解压后会发现里面有很多ply文件,文件名中的数字代表角度,比如045就是45°拍摄的。我们使用000和045两个点云文件,替换掉之前的single-depth-1.ply和single-depth-2.ply,然后直接按照之前的步骤编译运行就好了。当然是不可能的,事情没有这么简单!!!
之前的single-depth-1.ply和single-depth-2.ply的点云文件是按照二进制方式存储的,可以用notepad++打开如下:
其中第二行的format binary_little_endian 1.0指明了点云的文件格式,常用的有三种,大家可以自己百度,这一种看前缀就知道是二进制的存储。可以看到下面的都是乱码。再打开我们的兔子点云文件:
可以看到这里的格式是format ascii 1.0,是使用ascii进行编码的,没错,如果你仔细阅读斯坦福数据集的介绍,他们就说明了:For convenience, we have represented most of these PLY files in their ASCII formats. Choosing ASCII makes it possible for someone unfamiliar with it to get a feel for the file format, and it avoids the problem of using the correct big-endian vs. little-endian byte orders. 意思就是我们大部分都是用ASCII编码,因为二进制编码有两种格式,避免你读取的时候造成错误。
那么这就要求我们去修改demo.cu文件。我们打开文件,找到main函数,需要修改以下两个部分:
int num_pts = 0;
for (int line_idx = 0; line_idx < 7; ++line_idx) {
std::string line_str;
std::getline(pointcloud_file, line_str);
if (line_idx == 2) {
std::istringstream tmp_line(line_str); //istringstream 是从字符串读 https://blog.csdn.net/sinat_30071459/article/details/50755710
std::string tmp_line_prefix; //输出前面的两部分
tmp_line >> tmp_line_prefix; //输出element
tmp_line >> tmp_line_prefix; //输出vertex
tmp_line >> num_pts; //点云的数目(对于点云1是257179)
}
在这里要将7改为24,将下面的line_idx=2中的2改为7,为什么要做这个修改呢,首先要明白这部分代码的作用是什么。这部分是读ply文件的头部,也就是header,如果你百度ply文件格式的话就会知道,header的作用就是介绍ply文件的一些配置。因为我们是从文件中读取,因此这部分先读出来我们才能读下面的数据。而中间部分的代码其实是为了读出点云中的点的数目,如果你往前翻看两个文件的截图,就会明白一个在第三行(下标是2)的第三个,是252179,而第二个是第18行(下标是17)的第三个,是40256。这就是以上修改的原因。
float * pts = new float[num_pts * 3]; // Nx3 matrix saved as float array (row-major order) Nx3矩阵保存为float数组(行主顺序)
pointcloud_file.read((char*)pts, sizeof(float) * num_pts * 3);
pointcloud_file.close();
//pointcloud_file.read((char*)pts, sizeof(float) * num_pts * 3);
for(int i=0;i<num_pts*3; i++)
{
float a;
pointcloud_file>>pts[i];
//std::cout<<pts[i]<<std::endl;
}
我们将其中的读文件那一行改为下面的读取方式,可以看出上面的读取方式是使用了read函数,这里其实就是c++中的ifstream函数,这个读取文件流可以读取二进制也可以读取文本文件,read函数就是用来读取二进制文件,而下面的直接使用>>是用来读取文本文件的,这就是改写的原因。
以上这两点是我通过将代码改成标准c++后实验出来的,最后的确可以训练出描述子,完成匹配。