本文是在对点云处理时,为了方便对选定文件夹下特定格式文件转换成pcd类型,所写的小工具。
特点是:
1.能获得指定文件夹下的指定类型的文件,并对文件进行类型转换
2.目前支持转换成pcd文件,源文件格式可以为 obj 和自定义的文件类型(假设前 n 行 为无效数据行,控制台下可以以参数 -iv n 形式指定)
3.可以将自定义文件类型数据读入到内存里,返回点云智能指针。
4.只支持 ascii 文本格式
需要说明的是:以下代码依赖 PCL 点云库 和 boost 库,boost库同时也是 pcl 库的依赖库,所以只需要配置 pcl 库。
raw2pclType.h 文件
#pragma once
#include <vector>
#include <string>
#include <fstream>
#include <pcl/io/pcd_io.h>
#include <pcl/io/obj_io.h>
#include <iostream>
#include <memory>
#include <iomanip>
#include <pcl/console/parse.h>
#include <pcl/io/obj_io.h>
#include <pcl/io/pcd_io.h>
#include <boost/filesystem.hpp>
#include <boost/xpressive/xpressive_dynamic.hpp>
namespace fg
{
enum PcDataType
{
INVALID_TYPE, PCD, OBJ, MEMORY, RAW
};
void parseCommandLine(int argc, char *argv[], PcDataType &srcTp, PcDataType &dsTp, std::string &ipth, int &invalidRows, std::string &opth, bool &isRecursive);
void getDirectoryTreeFormat(const boost::filesystem::path &src, std::vector<std::string> &directoryTree, const std::string &form, const bool isRecursive);
std::string enum2string(const PcDataType pct);
class PointCloudDataFormatTrans
{
public:
PointCloudDataFormatTrans(const std::string &ifile, const int inValidRows, const std::string &outDir, const PcDataType srcTp, const PcDataType dsTp);
~PointCloudDataFormatTrans() {}
pcl::PointCloud<pcl::PointXYZ>::Ptr run();
private:
std::string m_ifile;
std::string m_outDir;
PcDataType m_srcTp;
PcDataType m_dsTp;
int m_inValidRows;
};
}
raw2pclType.cpp 文件
#include "raw2pclType.h"
namespace fg
{
void showHelp(char *filename)
{
std::cout << std::endl;
std::cout << "***************************************************************************" << std::endl;
std::cout << "* *" << std::endl;
std::cout << "* Correspondence Grouping Tutorial - Usage Guide *" << std::endl;
std::cout << "* *" << std::endl;
std::cout << "***************************************************************************" << std::endl << std::endl;
std::cout << "Usage: " << filename << " filePathName -f format[ obj or pcd ]" << std::endl << std::endl;
std::cout << "Options:" << std::endl;
std::cout << " -h(optional): Show this help." << std::endl;
std::cout << " -r(optional): Recursively find the src-type files that will be converted,otherwise inside current folder default." << std::endl;
std::cout << " -st: the src-type of files that will be converted,supporting obj and any pure three-demension-data file." << std::endl;
std::cout << " -dt: the dst-type of files that will be converted,only supporting pcd format." << std::endl;
std::cout << " -i: the direct including all files that need to be converted." << std::endl;
std::cout << " -iv(optional): the number of beginning-rows of invalid data for src file,default 0." << std::endl;
std::cout << " -o(optional): the direct that all tranformed files to be outputted to." << std::endl;
std::cout << " for example: raw2pclType_v2.exe -r -st[raw,obj] -dt[pcd] -i d:/ddf/in -o d:/out -iv 6" << std::endl;
}
void parseCommandLine(int argc, char *argv[], PcDataType &srcTp, PcDataType &dsTp, std::string &ipth, int &invalidRows, std::string &opth,bool &isRecursive)
{
//Show help
if (pcl::console::find_switch(argc, argv, "-h"))
{
showHelp(argv[0]);
exit(0);
}
if (argc<3)
{
std::cout << "number of parameters is incorrect ! \n";
showHelp(argv[0]);
exit(-1);
}
std::string opt;
if (pcl::console::parse_argument(argc, argv, "-o", opt) != -1)
opth = opt;
else
opth = std::string();
std::string iv;
if (pcl::console::parse_argument(argc, argv, "-iv", iv) != -1)
invalidRows = std::stoi(iv);
else
invalidRows = 0;
if (pcl::console::find_switch(argc, argv, "-r"))
isRecursive = true;
else
isRecursive = false;
std::string ipt;
if (pcl::console::parse_argument(argc, argv, "-i", ipt) != -1)
ipth = ipt;
else
{
std::cout << "No files path! \n";
showHelp(argv[0]);
exit(-1);
}
std::string srcType, dsType;
if (pcl::console::parse_argument(argc, argv, "-st", srcType) != -1)
{
if (srcType=="memory")
{
std::cout << "format is not supported! \n";
showHelp(argv[0]);
exit(-1);
}
else if (srcType.compare("pcd")==0)
{
srcTp = PcDataType::PCD;
}
else if (srcType.compare("obj") == 0)
{
srcTp = PcDataType::OBJ;
}
else if (srcType.compare("raw")==0)
{
srcTp = PcDataType::RAW;
}
else
{
std::cout << "format is not supported ! \n";
showHelp(argv[0]);
exit(-1);
}
}
else
{
std::cout << "target format is missing! \n";
showHelp(argv[0]);
exit(-1);
}
if (pcl::console::parse_argument(argc, argv, "-dt", dsType) != -1)
{
if (dsType == "memory")
{
std::cout << "format is not supported! \n";
showHelp(argv[0]);
exit(-1);
}
else if (dsType.compare("pcd") == 0)
{
dsTp = PcDataType::PCD;
}
/*else if (dsType.compare("obj") == 0)
{
dsTp = PcDataType::OBJ;
}*/
else
{
std::cout << "format is not supported ! \n";
showHelp(argv[0]);
exit(-1);
}
}
else
{
std::cout << "target format is missing! \n";
showHelp(argv[0]);
exit(-1);
}
}
bool notPCD(const boost::filesystem::path &src)
{
if (src.has_extension())
{
const boost::filesystem::path extFile = src.extension();
std::string strExt = extFile.string();
if (strExt.compare(".pcd") == 0)
return false;
}
return true;
}
void getDirectoryTreeFormat(const boost::filesystem::path &src, std::vector<std::string> &directoryTree, const std::string &form, const bool isRecursive)
{
boost::xpressive::sregex reg = boost::xpressive::sregex::compile(std::string(".*") + form);
boost::filesystem::directory_iterator end_itr; // 缺省构造生成一个结束迭代器
for (boost::filesystem::directory_iterator it(src); it != end_itr; ++it)
{
if (boost::filesystem::is_directory(it->status()))
{
if (isRecursive)
{
getDirectoryTreeFormat(it->path(), directoryTree, form, isRecursive);
}
}
else if (boost::filesystem::is_regular_file(it->status()) && (boost::xpressive::regex_match(it->path().string(), reg))&& notPCD(it->path()))
{
directoryTree.push_back(it->path().string());
}
}
}
std::string enum2string(const PcDataType pct)
{
using string = std::string;
switch (pct)
{
case PcDataType::PCD:
return string("pcd");
case PcDataType::OBJ:
return string("obj");
case PcDataType::MEMORY:
return string("memory");
case PcDataType::RAW:
return string();
default:
return string();
}
}
PointCloudDataFormatTrans::PointCloudDataFormatTrans(const std::string &ifile, const int inValidRows, const std::string &outDir, const PcDataType srcTp, const PcDataType dsTp):
m_srcTp(srcTp), m_dsTp(dsTp), m_outDir(outDir),m_ifile(ifile), m_inValidRows(inValidRows)
{}
pcl::PointCloud<pcl::PointXYZ>::Ptr fg::PointCloudDataFormatTrans::run()
{
using BoostPath = boost::filesystem::path;
//路径构造
BoostPath ptLocal(m_ifile);
BoostPath title;
BoostPath dir = ptLocal.branch_path();
BoostPath extName;
if (ptLocal.has_extension())
{
title = ptLocal.stem();
extName = ptLocal.extension();
}
else
title = ptLocal.leaf();
std::string ofPathName;
if (m_outDir.empty())
{
ofPathName = dir.string() + std::string("\\") + title.string() + std::string(".") + enum2string(m_dsTp);
}
else
{
ofPathName = m_outDir + std::string("\\") + title.string() + std::string(".") + enum2string(m_dsTp);
}
//数据读取
pcl::PointCloud<pcl::PointXYZ>::Ptr m_cloudData(new pcl::PointCloud<pcl::PointXYZ>);
m_cloudData->clear();
m_cloudData->reserve(100000);
switch (m_srcTp)
{
case fg::OBJ:
{
pcl::OBJReader reader;
reader.read(m_ifile, *m_cloudData);
break;
}
case fg::RAW:
{
std::ifstream infile;
infile.open(m_ifile);
assert(infile.is_open());
std::string s;
float fDataX, fDataY, fDataZ;
for (size_t i = 0; i < m_inValidRows; i++)
getline(infile, s);
while (getline(infile, s))
{
replace(s.begin(), s.end(), ',', ' ');
std::stringstream ss(s);
ss >> fDataX;
ss >> fDataY;
ss >> fDataZ;
pcl::PointXYZ pointTmp(fDataX, fDataY, fDataZ);
m_cloudData->push_back(pointTmp);
}
infile.close();
break;
}
default:
{
std::cout << "the postfix of the inputfile is not supported !" << std::endl;
exit(-1);
}
}
if (m_dsTp == MEMORY)
return m_cloudData;
std::string postfix;
switch (m_dsTp)
{
case PCD:
{
pcl::PCDWriter writer;
writer.write(ofPathName, *m_cloudData);
break;
}
/*case OBJ:
{
pcl::OBJWriter writer;
writer.write(ofPathName, *m_cloudData);
break;
}*/
default:
{
std::cout << "the postfix of the inputfile is not supported !" << std::endl;
exit(-1);
}
}
return m_cloudData;
}
}
主文件 main.cpp
#include "raw2pclType.h"
int main(int argc, char *argv[])
{
using string = std::string;
using PcDataType = fg::PcDataType;
PcDataType srcTp = PcDataType::INVALID_TYPE, dsTp = PcDataType::INVALID_TYPE;
string ipth, opth;
bool isRecursive = false;
int inValidRows = 0;
fg::parseCommandLine(argc, argv, srcTp, dsTp, ipth, inValidRows, opth, isRecursive);
std::vector<std::string> filesPath;
using BoostPath = boost::filesystem::path;
BoostPath ipt(ipth);
fg::getDirectoryTreeFormat(ipt, filesPath, fg::enum2string(srcTp), isRecursive);
for (auto it = filesPath.cbegin(); it != filesPath.cend(); it++)
{
fg::PointCloudDataFormatTrans pointCloudDataFormatTrans(*it, inValidRows, opth, srcTp, dsTp);
pcl::PointCloud<pcl::PointXYZ>::Ptr pc = pointCloudDataFormatTrans.run();
}
}
在vs下编译成功后,运行可执行文件后,效果如下,使用方法如下图说明及示例: