144 lines
4.0 KiB
C++
144 lines
4.0 KiB
C++
#ifndef POINT_CLOUD_CONVERTER_H
|
||
#define POINT_CLOUD_CONVERTER_H
|
||
|
||
#include <string>
|
||
#include <vector>
|
||
#include <memory>
|
||
|
||
/**
|
||
* @brief 简单的 3D 点结构
|
||
*/
|
||
struct Point3D
|
||
{
|
||
float x, y, z;
|
||
Point3D() : x(0), y(0), z(0) {}
|
||
Point3D(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
|
||
};
|
||
|
||
/**
|
||
* @brief 带颜色的 3D 点结构
|
||
*/
|
||
struct Point3DRGB
|
||
{
|
||
float x, y, z;
|
||
uint8_t r, g, b;
|
||
Point3DRGB() : x(0), y(0), z(0), r(255), g(255), b(255) {}
|
||
Point3DRGB(float _x, float _y, float _z, uint8_t _r = 255, uint8_t _g = 255, uint8_t _b = 255)
|
||
: x(_x), y(_y), z(_z), r(_r), g(_g), b(_b) {}
|
||
};
|
||
|
||
/**
|
||
* @brief 简单的点云容器
|
||
*/
|
||
template<typename PointT>
|
||
class SimplePointCloud
|
||
{
|
||
public:
|
||
std::vector<PointT> points;
|
||
std::vector<int> lineIndices; // 每个点所属的线索引
|
||
|
||
void clear() { points.clear(); lineIndices.clear(); }
|
||
size_t size() const { return points.size(); }
|
||
bool empty() const { return points.empty(); }
|
||
void reserve(size_t n) { points.reserve(n); lineIndices.reserve(n); }
|
||
void push_back(const PointT& pt) { points.push_back(pt); }
|
||
void push_back(const PointT& pt, int lineIdx) {
|
||
points.push_back(pt);
|
||
lineIndices.push_back(lineIdx);
|
||
}
|
||
};
|
||
|
||
using PointCloudXYZ = SimplePointCloud<Point3D>;
|
||
using PointCloudXYZRGB = SimplePointCloud<Point3DRGB>;
|
||
|
||
/**
|
||
* @brief 点云数据转换器
|
||
* 负责加载 txt 和 pcd 格式的点云文件
|
||
*/
|
||
class PointCloudConverter
|
||
{
|
||
public:
|
||
PointCloudConverter();
|
||
~PointCloudConverter();
|
||
|
||
/**
|
||
* @brief 从 txt 文件加载点云(使用 CloudUtils)
|
||
*/
|
||
int loadFromTxt(const std::string& fileName, PointCloudXYZ& cloud);
|
||
int loadFromTxt(const std::string& fileName, PointCloudXYZRGB& cloud);
|
||
|
||
/**
|
||
* @brief 从 pcd 文件加载点云(简单 ASCII/Binary 解析)
|
||
*/
|
||
int loadFromPcd(const std::string& fileName, PointCloudXYZ& cloud);
|
||
int loadFromPcd(const std::string& fileName, PointCloudXYZRGB& cloud);
|
||
|
||
/**
|
||
* @brief 根据文件扩展名自动选择加载方式
|
||
*/
|
||
int loadFromFile(const std::string& fileName, PointCloudXYZ& cloud);
|
||
int loadFromFile(const std::string& fileName, PointCloudXYZRGB& cloud);
|
||
|
||
/**
|
||
* @brief 保存点云到 txt 文件(使用 CloudUtils)
|
||
*/
|
||
int saveToTxt(const std::string& fileName, const PointCloudXYZ& cloud, int lineNum, int linePtNum);
|
||
|
||
/**
|
||
* @brief 旋转点云(行列转置 + 交换XY)
|
||
* @param cloud 输入点云
|
||
* @param rotatedCloud 输出旋转后的点云
|
||
* @param lineNum 原始线数
|
||
* @param linePtNum 原始每线点数
|
||
* @param newLineNum 输出新的线数
|
||
* @param newLinePtNum 输出新的每线点数
|
||
*/
|
||
int rotateCloud(const PointCloudXYZ& cloud, PointCloudXYZ& rotatedCloud,
|
||
int lineNum, int linePtNum, int& newLineNum, int& newLinePtNum);
|
||
|
||
/**
|
||
* @brief 获取最后的错误信息
|
||
*/
|
||
std::string getLastError() const { return m_lastError; }
|
||
|
||
/**
|
||
* @brief 获取加载的点云数量
|
||
*/
|
||
size_t getLoadedPointCount() const { return m_loadedPointCount; }
|
||
|
||
/**
|
||
* @brief 获取加载的线数量
|
||
*/
|
||
int getLoadedLineCount() const { return m_loadedLineCount; }
|
||
|
||
private:
|
||
/**
|
||
* @brief 获取文件扩展名(小写)
|
||
*/
|
||
std::string getFileExtension(const std::string& fileName);
|
||
|
||
/**
|
||
* @brief 解析 PCD 文件头
|
||
*/
|
||
struct PcdHeader
|
||
{
|
||
int width = 0;
|
||
int height = 1;
|
||
int points = 0;
|
||
bool isBinary = false;
|
||
bool hasRgb = false;
|
||
std::vector<std::string> fields;
|
||
std::vector<int> fieldSizes;
|
||
std::vector<char> fieldTypes;
|
||
int pointSize = 0;
|
||
};
|
||
|
||
bool parsePcdHeader(std::ifstream& file, PcdHeader& header);
|
||
|
||
std::string m_lastError;
|
||
size_t m_loadedPointCount;
|
||
int m_loadedLineCount;
|
||
};
|
||
|
||
#endif // POINT_CLOUD_CONVERTER_H
|