个人解析代码GitHub:https://github.com/ybgdgh/s3dis_semantic
S3DIS数据集是斯坦福大学开发的带有像素级语义标注的语义数据集,包含了rgb,depth,3d点云、mesh等。
官网:http://buildingparser.stanford.edu/dataset.html
官网github:https://github.com/alexsax/2D-3D-Semantics
还原点云数据有多种方式,可以通过直接解析自带的mat文件进行解析,也可以通过合成rgb和深度图进行解析。本文以Area_1数据为例。
数据集自带的mat文件包含了每一label的点云坐标、rgb,标注、物体体积、是否占有能属性组成。数据结构如下:
该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等信息。在这里将所有对象的数据分别存入不同文件(避免文件过大)
通过这种方式,将点云文件转化为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内存仍然很卡。
之前一直在用这种方式做,调了整整两天的程序终于调通了,结果发现数据中的depth很有问题,合成的图片深度分层很严重,而且分层比较均匀,不像是程序的问题。采用的方法是通过读取data文件夹下的pose.json文件获取对应的相机位姿,再根据相机内参,将depth投影到空间去,并附上rgb信息。然而最后因结果不好而放弃。且自己合成点云非常消耗计算量,电脑跑一会就卡的要死,最好不要采用这种方式,直接使用mat文件中的数据即可。