S3DIS数据集解析为点云

S3DIS数据集解析为点云

  • S3DIS数据集解析
      • 数据格式
    • 1.直接解析pointcloud.mat文件
    • 2.通过data文件夹中的pose合成rgb和depth

个人解析代码GitHub:https://github.com/ybgdgh/s3dis_semantic

S3DIS数据集解析

S3DIS数据集是斯坦福大学开发的带有像素级语义标注的语义数据集,包含了rgb,depth,3d点云、mesh等。

官网:http://buildingparser.stanford.edu/dataset.html

官网github:https://github.com/alexsax/2D-3D-Semantics

数据格式

S3DIS数据集解析为点云_第1张图片

还原点云数据有多种方式,可以通过直接解析自带的mat文件进行解析,也可以通过合成rgb和深度图进行解析。本文以Area_1数据为例。

1.直接解析pointcloud.mat文件

数据集自带的mat文件包含了每一label的点云坐标、rgb,标注、物体体积、是否占有能属性组成。数据结构如下:
S3DIS数据集解析为点云_第2张图片
该mat文件包含一个struct结构体,结构体又往下分级。

可以用python直接解析该mat文件,本人对python不太熟悉,因此最后采用了将该mat文件转化为json脚本的形式,通过c++进行解析。

通过matlab解析json非常简单,只需要下载安装一个插件JSONlab,对应链接:https://github.com/fangq/jsonlab/#installation,

添加到matlab的toolkit文件加中,再将路径添加进行即可。matlab程序如下:

load('pointcloud.mat')
name_ALL = Area_1.Disjoint_Space;
for i=1:1:44
    name=savejson('',name_ALL(i));
    fid=fopen(['Adata_',num2str(i),'.json'],'w+');
    fprintf(fid,'%s',name);
    fclose(fid);
    fprintf('%s \n',i);
end

本次只针对一个场景即Area_1进行解析,因此只采集了object所有对象下的结构体,该结构体下又包含多个子类,每一类都有对应的一套属性。

每个对象的内容如下:

{
	"name": "conferenceRoom_1",
	"AlignmentAngle": -0,
	"color": [0.5,0.5,0],
	"object": [
		{
			"name": "beam_1",
			"RGB_color": [
				[71,64,54],
				[68,64,52],
				...
				...
				[-15.296,40.53,2.19]
				]
			]
		}
	]
}

object结构体下包含了其他如坐标、Voxels等信息。在这里将所有对象的数据分别存入不同文件(避免文件过大)

S3DIS数据集解析为点云_第3张图片
通过这种方式,将点云文件转化为json格式,再通过c++读取即可。程序如下:

json解析函数根据官方提供的代码进行了修改,官方代码只是用来解析pose.josn数据的,这里用boost::property_tree::ptree来解析json格式。

#ifndef SEMANTIC2D3D_UTILS_H
#define SEMANTIC2D3D_UTILS_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 

namespace Utils
{

/** Gets the RGB_color from a pose file ptree and returns it**/
inline bool
getRGBcolor(const boost::property_tree::ptree &pt, std::vector &RGB)
{
    // Read in RGB_color
    Eigen::Vector3d rgb_point;
    int i = 0;

    boost::property_tree::ptree object = pt.get_child("object");
    BOOST_FOREACH (boost::property_tree::ptree::value_type &vtt, object)
    {
        boost::property_tree::ptree pt_tree = vtt.second;
        boost::property_tree::ptree RGB_color = pt_tree.get_child("RGB_color");
        BOOST_FOREACH (boost::property_tree::ptree::value_type &v, RGB_color)
        {
            boost::property_tree::ptree tree = v.second;
            BOOST_FOREACH (boost::property_tree::ptree::value_type &vt, tree)
            {
                rgb_point[i] = vt.second.get_value();
                i++;
            }
            i = 0;
            // std::cout << rgb_point.transpose() << std::endl;
            RGB.push_back(rgb_point);
        }
    }

    return true;
}

inline bool
getXYZpoints(const boost::property_tree::ptree &pt, std::vector &XYZ)
{
    // Read in XYZ_color
    Eigen::Vector3d xyz_point;
    int i = 0;

    boost::property_tree::ptree object = pt.get_child("object");
    BOOST_FOREACH (boost::property_tree::ptree::value_type &vtt, object)
    {
        boost::property_tree::ptree pt_tree = vtt.second;
        boost::property_tree::ptree point = pt_tree.get_child("points");
        BOOST_FOREACH (boost::property_tree::ptree::value_type &v, point)
        {
            boost::property_tree::ptree tree = v.second;
            BOOST_FOREACH (boost::property_tree::ptree::value_type &vt, tree)
            {
                xyz_point[i] = vt.second.get_value();
                i++;
            }
            i = 0;
            // std::cout << rgb_point.transpose() << std::endl;
            XYZ.push_back(xyz_point);
        }
    }

    return true;
}

/** Load in the json pose files into a boost::ptree **/
inline boost::property_tree::ptree
loadPoseFile(const std::string &json_filename)
{
    // Read in view_dict
    boost::property_tree::ptree pt;
    std::ifstream in(json_filename);
    std::stringstream buffer;
    buffer << in.rdbuf();
    read_json(buffer, pt);
    return pt;
}

/** Debugging function to print out a boost::ptree **/
void print(boost::property_tree::ptree const &pt)
{
    using boost::property_tree::ptree;
    ptree::const_iterator end = pt.end();
    for (ptree::const_iterator it = pt.begin(); it != end; ++it)
    {
        std::cout << it->first << ": " << it->second.get_value() << std::endl;
        print(it->second);
    }
}
} // namespace Utils

#endif // #ifndef SEMANTIC2D3D_UTILS_H

以上给出了解析json中点云坐标和rgb的程序。可根据文件树添加其他数据的解析程序,json的解析方式是一样的,只需要调整一下解析程序中的层数和对应的name即可。

主函数如下,主要是通过调用点云数据和rgb数据进行整体点云的拼接。由于点云数量过大,因此最后还是按文件分别保存了pcd文件。

#include 
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"

#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "pcl_utils.h"


using namespace std;
using namespace Eigen;
using namespace cv;
using namespace pcl;


int main(int argc, char **argv)
{

    string filename = "point_data/";

    vector files_json; //存放文件路径

    glob(filename, files_json, true);

    // 使用智能指针,创建一个空点云。这种指针用完会自动释放。
    PointCloud::Ptr cloud(new PointCloud);
    // PointCloud::Ptr cloud_sum(new PointCloud);


    // for (int i = 0; i < files_json.size(); i++)
    // {
        // cout << "name : " << files_json[i] << endl;
        // pcl::io::loadPCDFile(files_json[i], *cloud);
        // *cloud_sum = *cloud_sum + *cloud;
        // cloud->points.clear();
        // cout << "sum " << i << " / " << files_json.size() <<  "done" << endl;
    // }
    // pcl::io::savePCDFile("cloud_sum.pcd", *cloud_sum);


    boost::shared_ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));

    viewer->setBackgroundColor(0, 0, 0);

    for (int i = 2; i < files_json.size(); i++)
    {
        boost::property_tree::ptree pose_pt = Utils::loadPoseFile(files_json[i]);

        string name = pose_pt.get("name");

        cout << "name : " << name << endl;
        // string global_name = pose_pt.get("global_name");

        std::vector RGB_color;
        if (!Utils::getRGBcolor(pose_pt, RGB_color))
            ;

        std::vector points;
        if (!Utils::getXYZpoints(pose_pt, points))
            ;
        cout << "read date done.." << endl;
        // cout << "global_name : " << global_name << endl;
        // cout << "RGB_color_size : " << RGB_color.size() << endl;
        // cout << "points_size : " << points.size() << endl;

        for (int j = 0; j < RGB_color.size(); j++)
        {
            pcl::PointXYZRGB point;

            point.x = points[j](0);
            point.y = points[j](1);
            point.z = points[j](2);

            point.b = RGB_color[j](2);
            point.g = RGB_color[j](1);
            point.r = RGB_color[j](0);

            cloud->push_back(point);
        }
        cout << i << "point number :" << cloud->points.size() << endl;

        String ss = "pointcloud_" + name + ".pcd";
        pcl::io::savePCDFile(ss, *cloud);

        // 清除数据并退出
        cloud->points.clear();
        cout << "Point cloud saved." << endl;
        cout << "next pcd reading..." << endl;
    }

    cloud->width = 1;
    cloud->height = cloud->points.size();

    depth_cloud->width = 1;
    depth_cloud->height = cloud->points.size();

    pcl::visualization::PointCloudColorHandlerRGBField rgb_cloud(cloud);
    viewer->addPointCloud(cloud, rgb_cloud, "sample cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "sample cloud");
    viewer->addCoordinateSystem(1.0);

    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(100000));
    }
    cv::waitKey(0);
    viewer->removeAllPointClouds();

    return 0;
}

由此可以生成以文件为单位的点云数据,取其中一个生成的点云如图:

程序中注释的部分为最后将所有的点云pcd文件合成一个点云的代码,最后Area_1的整体点云效果如图:

本人i7-8700HQ+16g内存仍然很卡。

2.通过data文件夹中的pose合成rgb和depth

之前一直在用这种方式做,调了整整两天的程序终于调通了,结果发现数据中的depth很有问题,合成的图片深度分层很严重,而且分层比较均匀,不像是程序的问题。采用的方法是通过读取data文件夹下的pose.json文件获取对应的相机位姿,再根据相机内参,将depth投影到空间去,并附上rgb信息。然而最后因结果不好而放弃。且自己合成点云非常消耗计算量,电脑跑一会就卡的要死,最好不要采用这种方式,直接使用mat文件中的数据即可。

你可能感兴趣的:(slam,语义地图)