一. 环境介绍
1.Visual Studio 2019
2.PCL、Boost
3.悉灵相机MV-EB435i,SDK版本Mv3dRgbd_V1.0.0_Win
具体环境配置:
二. 解析点云数据及存储
由于相机通过USB接入,在设备类型选择DeviceType_USB:
ASSERT_OK(MV3D_RGBD_GetDeviceList(DeviceType_USB, &devs[0], nDevNum, &nDevNum));
参考SDK中给出的结构体参数,可以得到图像的详细信息:
在相机图像MV3D_RGBD_IMAGE_DATA数据中,有图像宽、图像高、相机输出的图像数据、图像数据长度(字节)、帧号、设备上报的时间戳等信息,通过图像高、宽、图像数据长度可以计算图像点数,以供后续使用。为了得到图像数据,对pData指针进行解析,得到图像数据。
由于相机不输出点云数据,采用深度图数据转换成点云数据:
nRet = MV3D_RGBD_MapDepthToPointCloud(handle, &stFrameData.stImageData[i], &stPointCloudImage);
采用PCL的点云结构存储解析得到的相机点云数据,并对明显的无效数据进行过滤:
调用PCL存文件接口,将点云文件存储成pcd格式:
pcl::io::savePCDFileASCII(to_string(num)+".pcd", pointCloud);
三. 代码
main.cpp:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <stdio.h>
#include "../common/common.hpp"
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
using namespace std;
int main()
{
ASSERT_OK(MV3D_RGBD_Initialize());
unsigned int nDevNum = 0;
ASSERT_OK(MV3D_RGBD_GetDeviceNumber(DeviceType_USB, &nDevNum));
LOGD("MV3D_RGBD_GetDeviceNumber success! nDevNum:%d.", nDevNum);
ASSERT(nDevNum);
std::vector<MV3D_RGBD_DEVICE_INFO> devs(nDevNum);
ASSERT_OK(MV3D_RGBD_GetDeviceList(DeviceType_USB, &devs[0], nDevNum, &nDevNum));
for (unsigned int i = 0; i < nDevNum; i++)
{
LOG("Index[%d]. SerialNum[%s] IP[%s] name[%s].\r\n", i, devs[i].chSerialNumber, devs[i].SpecialInfo.stNetInfo.chCurrentIp, devs[i].chModelName);
}
void* handle = NULL;
unsigned int nIndex = 0;
ASSERT_OK(MV3D_RGBD_OpenDevice(&handle, &devs[nIndex]));
LOGD("OpenDevice success.");
ASSERT_OK(MV3D_RGBD_Start(handle));
LOGD("Start work success.");
int num = 0;
bool exit_flag = TRUE;
MV3D_RGBD_FRAME_DATA stFrameData = { 0 };
while (exit_flag)
{
pcl::PointCloud<pcl::PointXYZ> pointCloud;
int nRet = MV3D_RGBD_FetchFrame(handle, &stFrameData, 5000);
if (MV3D_RGBD_OK == nRet)
{
for (int i = 0; i < stFrameData.nImageCount; i++)
{
if (ImageType_Depth == stFrameData.stImageData[i].enImageType)
{
MV3D_RGBD_IMAGE_DATA stPointCloudImage;
nRet = MV3D_RGBD_MapDepthToPointCloud(handle, &stFrameData.stImageData[i], &stPointCloudImage);
float* pPtr = (float*)stPointCloudImage.pData;
int nPointNum = stPointCloudImage.nDataLen / (sizeof(float) * 3);
LOGD("Start write Points of %d framenum!", stPointCloudImage.nFrameNum);
for (int nPntIndex = 0; nPntIndex < nPointNum; ++nPntIndex)
{
if (pPtr[nPntIndex * 3 + 0] > 6000 || pPtr[nPntIndex * 3 + 1] > 6000 || pPtr[nPntIndex * 3 + 2] > 6000)continue;
if (pPtr[nPntIndex * 3 + 0] != 0 || pPtr[nPntIndex * 3 + 1] != 0 || pPtr[nPntIndex * 3 + 2] != 0) {
pcl::PointXYZ point;
point.x = pPtr[nPntIndex * 3 + 0];
point.y = pPtr[nPntIndex * 3 + 1];
point.z = pPtr[nPntIndex * 3 + 2];
pointCloud.points.push_back(point);
}
}
pointCloud.width = pointCloud.points.size();
pointCloud.height = 1;
pcl::io::savePCDFileASCII(to_string(num)+".pcd", pointCloud);
LOGD("_MapDepthToPointCloud() Run Succeed: framenum (%d) height(%d) width(%d) len (%d)!", stPointCloudImage.nFrameNum,
stPointCloudImage.nHeight, stPointCloudImage.nWidth, stPointCloudImage.nDataLen);
}
if (MV3D_RGBD_OK != nRet)
{
break;
}
}
}
if (_kbhit())
{
exit_flag = FALSE;
}
num++;
}
ASSERT_OK(MV3D_RGBD_Stop(handle));
ASSERT_OK(MV3D_RGBD_CloseDevice(&handle));
ASSERT_OK(MV3D_RGBD_Release());
LOGD("Main done!");
return 0;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.9)
set(CMAKE_CXX_STANDARD 11)
project(storepointscloud)
set(BOOST_ROOT "C:/PCL 1.12.1/3rdParty/Boost")
find_package(Boost REQUIRED
COMPONENTS system filesystem thread)
find_package(PCL 1.3 REQUIRED)
set(SOURCE_FILES main.cpp)
include_directories(Include/)
include_directories(common/include)
include_directories(
${PCL_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
)
link_directories(Lib/Win64)
link_directories(common/lib/Win64)
link_directories(
${PCL_LIBRARY_DIRS}
${BOOST_LIBRARY_DIRS}
)
add_definitions(
${PCL_DEFINITIONS}
)
add_compile_definitions(NOMINMAX)
add_executable(storepointscloud ${SOURCE_FILES})
target_link_libraries(storepointscloud
${PCL_LIBRARIES}
${Boost_LIBRARIES}
)
target_link_libraries(storepointscloud Mv3dRgbd glfw3 opengl32 glu32)
四. 运行结果
可以看到在可执行文件目录下已经生成pcd格式的点云文件: