You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Halcon点云转unsigned char*序列化及MongoDB反序列化实现

问题描述

我用C++开发,从2D/3D传感器(比如Photoneo XL)采集数据,要通过MongoDB的GridFS存储图像和点云(因为数据量超16MB,得序列化成unsigned char*缓冲区)。为了避免存文件的耗时,直接把传感器输出变量转成字节处理。

软件采用微服务架构,一个服务负责采集并上传到MongoDB,其他服务通过ID引用访问数据。

图像的序列化/反序列化已经实现,代码如下:

图像序列化代码

QImage img = QImage("./smallimage.png");
mongocxx::gridfs::bucket bucket = db.gridfs_bucket();
auto uploader = bucket.open_upload_stream("sample_gridfs_file");
uploader.write((unsigned char*)img.bits(), img.sizeInBytes());

图像反序列化代码

while (auto length_read = downloader.read(buffer.get(), static_cast<std::size_t>(buffer_size))) 
{
    bytes_counter += static_cast<std::int32_t>(length_read);
    tmp_char = (unsigned char*)buffer.get();
    memcpy(array_char+cum_size,tmp_char, buffer_size);
    cum_size += buffer_size;
}
QImage out = QImage(array_char, img.width(), img.height(), img.format());

但处理点云时遇到困难:点云用Halcon采集,存在HTuple里,已经提取出X、Y、Z坐标的三个double*数组,需要把这些数据序列化成unsigned char*上传到MongoDB,之后再读取解码成新的double*数组重建点云。初始代码如下:

HalconCpp::ReadObjectModel3d("./point_cloud.ply", "m", HalconCpp::HTuple(), HalconCpp::HTuple(),&hv_ObjectModel3D, &hv_Status);

HalconCpp::GetObjectModel3dParams(hv_ObjectModel3D, "num_points", &numPoints);
HalconCpp::GetObjectModel3dParams(hv_ObjectModel3D, "point_coord_x", &pointsX);
HalconCpp::GetObjectModel3dParams(hv_ObjectModel3D, "point_coord_y", &pointsY);
HalconCpp::GetObjectModel3dParams(hv_ObjectModel3D, "point_coord_z", &pointsZ);
double* xArray = pointsX.DArr();
double* yArray = pointsY.DArr();
double* zArray = pointsZ.DArr();
点云序列化与反序列化解决方案

1. 点云序列化(上传到GridFS)

核心思路是先存储点的数量(方便反序列化时确定数据长度),再把三个double*数组按顺序拼接成连续字节流,直接写入GridFS。

实现代码

// 获取点的数量
int num_points = numPoints.I();

// 计算总字节数:点数量(int) + 3*点数量*double字节数
size_t total_bytes = sizeof(int) + 3 * num_points * sizeof(double);

// 分配缓冲区
std::unique_ptr<unsigned char[]> buffer(new unsigned char[total_bytes]);

// 第一步:写入点数量
memcpy(buffer.get(), &num_points, sizeof(int));

// 第二步:依次写入X、Y、Z数组
unsigned char* ptr = buffer.get() + sizeof(int);
memcpy(ptr, xArray, num_points * sizeof(double));
ptr += num_points * sizeof(double);
memcpy(ptr, yArray, num_points * sizeof(double));
ptr += num_points * sizeof(double);
memcpy(ptr, zArray, num_points * sizeof(double));

// 上传到GridFS
mongocxx::gridfs::bucket bucket = db.gridfs_bucket();
auto uploader = bucket.open_upload_stream("point_cloud_data");
uploader.write(buffer.get(), total_bytes);
uploader.close(); // 必须关闭流确保数据写入完成

2. 点云反序列化(从GridFS读取重建)

读取时先解析点的数量,再依次提取X、Y、Z的字节数据转成double*数组,最后用Halcon重建点云。

实现代码

// 假设已从GridFS下载完整数据到data缓冲区,data_size为总字节长度
int num_points;
memcpy(&num_points, data, sizeof(int));

// 分配X、Y、Z数组内存
std::unique_ptr<double[]> xArr(new double[num_points]);
std::unique_ptr<double[]> yArr(new double[num_points]);
std::unique_ptr<double[]> zArr(new double[num_points]);

// 解析数据
const unsigned char* ptr = data + sizeof(int);
memcpy(xArr.get(), ptr, num_points * sizeof(double));
ptr += num_points * sizeof(double);
memcpy(yArr.get(), ptr, num_points * sizeof(double));
ptr += num_points * sizeof(double);
memcpy(zArr.get(), ptr, num_points * sizeof(double));

// 用Halcon重建点云
HalconCpp::HTuple hv_X, hv_Y, hv_Z;
hv_X = HalconCpp::HTuple(num_points, xArr.get());
hv_Y = HalconCpp::HTuple(num_points, yArr.get());
hv_Z = HalconCpp::HTuple(num_points, zArr.get());

HalconCpp::HTuple hv_ObjectModel3D;
HalconCpp::CreateObjectModel3d("point_cloud", hv_X, hv_Y, hv_Z, HalconCpp::HTuple(), HalconCpp::HTuple(), &hv_ObjectModel3D);

关键注意事项

  • 字节序兼容:如果微服务运行在不同架构机器(如x86/ARM),需统一字节序(比如转大端),避免解析错误。可使用htobe32处理int,htobe64处理double,或自定义转换函数。
  • 内存安全:用智能指针(如std::unique_ptr)管理缓冲区,避免大数据量点云导致的内存泄漏。
  • 流操作规范:上传/下载GridFS流时必须关闭,否则会出现数据不完整问题。
  • HTuple转换校验:将double*转HTuple时,确保数组长度与点数量一致,防止越界。

内容的提问来源于stack exchange,提问作者Stefano Grossi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 00:30:44