问题描述:我们在开发有关pcl点云系统的时候,通常会遇到的问题就是如何将pcl、c++读取的点云数据或点云图像可视化到提前写好C#界面中。(不是显示到pcl自带的点云可视化窗口中)
在学习本文之前需要掌握一下知识点:
1、C++ dll动态库的开发
2、PCL点云读取和点云显示
3、C#与C++动态库之间的调用
0、首先系统启动时需要将系统窗口中用于可视化点云的控件句柄传递到dll动态库中实例化PCL中点云显示的类(class show{})
1、C#端通过文件选择功能将需要显示的pcd或ply文件
2、C#端将选择的文件地址传递给C++编译好的dll动态库文件中
3、dll动态库读取完文件或数据后将数据加载到已经实例化好的 show {} 类中,并通过钩子函数向C#端返回一个控制参数A
4、C#端接收到控制参数A后调用dll动态库中用于显示点云的接口将读取的点云数据可视化到C#端窗口中
本文提供了全套的可执行源码
源码链接:https://download.csdn.net/download/qq_43627520/83477939
有咨询方面的需求也可通过邮箱与我联系:[email protected]
c#窗口
0、界面启动时,加载委托函数实例化PCL中点云显示的类(class show{})
private void updata_dll_PointCloud(int itype, int model)
{
UpDataPointCloud(model);
}
// 定义后台委托
private delegate void deUpdate_ShowPointCloud(int type);
private void UpDataPointCloud(int type)
{
if (this.pictureBox1.InvokeRequired) //等待异步处理
{
deUpdate_ShowPointCloud ds = new deUpdate_ShowPointCloud(UpDataPointCloud);
this.Invoke(ds, new object[] { type });
}
else
{
IntPtr m_hwnd = (IntPtr)0;
// 点云界面初始化
if (0 == type)
{
if (pictureBox1.IsHandleCreated == true)
{
m_hwnd = pictureBox1.Handle;
dll_ShowPointCloud.EX_SysInit(m_hwnd, 0); //界面点云显示初始化
}
}
else if (1 == type)
{
Console.WriteLine("point show");
dll_ShowPointCloud.EX_PointCloud_Show(1);
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
DLL_ShowPointCloud.maindelegateCallBack = updata_dll_PointCloud;
// 初始化点云可视化界面
UpDataPointCloud(0);
}
1、C#端通过文件选择功能将需要显示的pcd或ply文件
2、C#端将选择的文件地址传递给C++编译好的dll动态库文件中
private void button1_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog file = new OpenFileDialog();
file.InitialDirectory = ".";
file.Filter = "所有文件(*.*)|*.*";
file.ShowDialog();
if (file.FileName != string.Empty)
{
pcdFile = file.FileName; //获得文件的绝对路径
label1.Text = pcdFile;
int res = dll_ShowPointCloud.EX_PointCloud_Init(pcdFile, 1);
if (res == 0)
{
label2.Text = "点云读取完毕";
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
#define DLL_API extern "C" _declspec(dllexport)
#include "PclShow.h"
PointCloudShowWindows* pointCloudShowWindows = NULL;
//设置钩子函数
DLL_API int __stdcall EX_PCLSHOW_SetCallback(PCLSHOW_PResHook callback, int imode)
{
try
{
pointCloudShowWindows->pCLSHOW_PResHook = callback;
return 1;
}
catch (...)
{
return 0;
}
}
//界面初始化
void loadFile(std::string path, pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
std::string fileType = path.substr(path.find_last_of('.') + 1);//获取文件后缀
if (fileType == "ply") {
if (pcl::io::loadPLYFile <pcl::PointXYZ>(path, *cloud) == -1)
{
std::cout << "Cloud reading .ply failed." << std::endl;
}
}
else if (fileType == "pcd") {
if (pcl::io::loadPCDFile <pcl::PointXYZ>(path, *cloud) == -1)
{
std::cout << "Cloud reading .pcd failed." << std::endl;
}
}
}
DLL_API int Sys_Init(void* ShowReDispWindow) {
try {
cout << "Sys_Init start" << endl;
pointCloudShowWindows = new PointCloudShowWindows();
int ShowSR = pointCloudShowWindows->PCL_SHOW_RESULT((HWND)ShowReDispWindow); //初始化结果
cout << "Sys_Init end"<< ShowSR << endl;
return ShowSR;
}
catch (...) {
return 0;
}
}
DLL_API int PointCloud_Show(int itype) {
try {
if (1 == itype) {
// 显示输入点云
pointCloudShowWindows->PCL_Show_InputCloud();
}
else {
//显示彩色点云
pointCloudShowWindows->PCL_Show_PointCloud();
}
return 1;
}
catch (...) {
return 0;
}
}
DLL_API int PointCloud_Init(char* filePathName) {
pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud(new pcl::PointCloud<pcl::PointXYZ>);
loadFile(filePathName, inputCloud);
cout << "filePathName"<< filePathName << endl;
pointCloudShowWindows->PCL_Updata_InputCloud(inputCloud);
return 0;
}
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//钩子函数
typedef UINT(WINAPI* PCLSHOW_PResHook)(int ival, int imode);
#define Random(x) (rand() % x)
//点云数据显示类
class PointCloudShowWindows
{
public:
PointCloudShowWindows();
~PointCloudShowWindows();
private:
boost::shared_ptr<pcl::visualization::PCLVisualizer> result_viewer;//要共享指针类型的,要不然,显示窗口会跳出MFC界面
vtkRenderWindow* result_viewer_win; //vtk渲染的窗口句柄
vtkRenderWindowInteractor* result_viewer_iren;//vtk交互的对象
int result_viewer_i_ui_w = 0;
int result_viewer_i_ui_h = 0;
boost::shared_ptr<pcl::visualization::PCLVisualizer> input_viewer;
vtkRenderWindow* input_viewer_win; //vtk渲染的窗口句柄
vtkRenderWindowInteractor* input_viewer_iren;//vtk交互的对象
int input_viewer_i_ui_w = 0;
int input_viewer_i_ui_h = 0;
private:
std::vector<pcl::PointCloud<pcl::PointXYZ>>clusters;
std::vector<std::vector<int>>Particle_index;
pcl::PointCloud<pcl::PointXYZ>::Ptr Input_cloud;
public:
int PCL_SHOW_RESULT(HWND ShowReDispWindow);
int PCL_SHOW_INPUT(HWND InputCloudDispWindow);
int PCL_Show_PointCloud();
int PCL_Updata_InputCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr InputCloud);
int PCL_Show_InputCloud();
int PCL_Get_Data(std::vector<pcl::PointCloud<pcl::PointXYZ>>cloud_clusters, std::vector<std::vector<int>>Particle_size_cluster_index, pcl::PointCloud<pcl::PointXYZ>::Ptr InputCloud);
//钩子函数
public:
PCLSHOW_PResHook pCLSHOW_PResHook;
};
#include "PclShow.h"
PointCloudShowWindows::PointCloudShowWindows()
{
}
PointCloudShowWindows::~PointCloudShowWindows()
{
}
int PointCloudShowWindows::PCL_Updata_InputCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr InputCloud) {
Input_cloud.reset(new pcl::PointCloud<pcl::PointXYZ>);
Input_cloud->resize(InputCloud->size());
Input_cloud = InputCloud;
pCLSHOW_PResHook(1, 1);
return 0;
}
int PointCloudShowWindows::PCL_Get_Data(std::vector<pcl::PointCloud<pcl::PointXYZ>>cloud_clusters, std::vector<std::vector<int>>Particle_size_cluster_index, pcl::PointCloud<pcl::PointXYZ>::Ptr InputCloud) {
/*clusters.clear();
Particle_index.clear();
*/
clusters = cloud_clusters;
Particle_index = Particle_size_cluster_index;
pCLSHOW_PResHook(1, 3);
return 0;
}
int PointCloudShowWindows::PCL_SHOW_INPUT(HWND InputCloudDispWindow)
{
try
{
input_viewer.reset(new pcl::visualization::PCLVisualizer("Input_Viewer", false));//初始化viewer对象
//m_viewer->setShowFPS(false);
input_viewer->addCoordinateSystem(1.0);
input_viewer->setBackgroundColor(255, 0, 0);//设置背景颜色
input_viewer->initCameraParameters();//初始化相机的参数
input_viewer_win = input_viewer->getRenderWindow();//将view中的渲染窗口的句柄传递给vtk window
input_viewer_iren = vtkRenderWindowInteractor::New();//初始化vtkwindow交互的对象
input_viewer->resetCamera();//使点云显示在屏幕中间,并绕中心操作
RECT Input_Window;
::GetClientRect(InputCloudDispWindow, &Input_Window);
input_viewer_i_ui_w = Input_Window.right - Input_Window.left;
input_viewer_i_ui_h = Input_Window.bottom - Input_Window.top;
input_viewer_win->SetSize(input_viewer_i_ui_w, input_viewer_i_ui_h);//根据当前窗口的大小设置vtk 窗口的大小
//m_win->SetSize(300, 300);//根据当前窗口的大小设置vtk 窗口的大小
input_viewer_win->SetParentId(InputCloudDispWindow);//设置vtk窗口的句柄
//input_viewer_iren->SetRenderWindow(input_viewer_win);//将vtk交互对象与vtk window绑定
input_viewer->createInteractor();
input_viewer_win->Render();//开始渲染
return 1;
}
catch (...)
{
return 0;
}
}
int PointCloudShowWindows::PCL_SHOW_RESULT(HWND ShowReDispWindow)
{
try
{
result_viewer.reset(new pcl::visualization::PCLVisualizer("Result_Viewer", false));//初始化viewer对象
//m_viewer->setShowFPS(false);
result_viewer->addCoordinateSystem(1.0);
result_viewer->setBackgroundColor(0, 0, 0);//设置背景颜色
result_viewer->initCameraParameters();//初始化相机的参数
result_viewer_win = result_viewer->getRenderWindow();//将view中的渲染窗口的句柄传递给vtk window
//result_viewer_iren = vtkRenderWindowInteractor::New();//初始化vtkwindow交互的对象
result_viewer->resetCamera();//使点云显示在屏幕中间,并绕中心操作
RECT ShowRe_Window;
::GetClientRect(ShowReDispWindow, &ShowRe_Window);
result_viewer_i_ui_w = ShowRe_Window.right - ShowRe_Window.left;
result_viewer_i_ui_h = ShowRe_Window.bottom - ShowRe_Window.top;
result_viewer_win->SetSize(result_viewer_i_ui_w, result_viewer_i_ui_h);//根据当前窗口的大小设置vtk 窗口的大小
//m_win->SetSize(300, 300);//根据当前窗口的大小设置vtk 窗口的大小
result_viewer_win->SetParentId(ShowReDispWindow);//设置vtk窗口的句柄
//result_viewer_iren->SetRenderWindow(result_viewer_win);//将vtk交互对象与vtk window绑定
result_viewer->createInteractor();
result_viewer_win->Render();//开始渲染
return 1;
}
catch (...)
{
return 0;
}
}
int PointCloudShowWindows::PCL_Show_PointCloud()
{
try
{
result_viewer->removeAllPointClouds();//将前一次点云移除
// 显示分割结果
pcl::PointCloud<pcl::PointXYZRGB>::Ptr pointXYZRBG(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::PointXYZRGB point;
for (int i = 2; i < Particle_index.size(); i++) {
for (int j = 0; j < Particle_index[i].size(); j++) {
int color_R = Random(255);
int color_G = Random(255);
int color_B = Random(255);
int id = Particle_index[i][j];
for (int h = 0; h < clusters[id].size(); h++) {
point.x = clusters[id].points[h].x;
point.y = clusters[id].points[h].y;
point.z = clusters[id].points[h].z;
point.r = color_R;
point.g = color_G;
point.b = color_B;
pointXYZRBG->push_back(point);
}
}
}
//windows_viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample"); // 用于改变显示点云的尺寸。用户可以利用该方法控制点云在视窗中的显示方式。
result_viewer->addPointCloud<pcl::PointXYZRGB>(pointXYZRBG); // 显示点云,其中fildColor为颜色显示
pcl::PointXYZRGB min_p, max_p; //用于存放三个轴的最小值,最大值
pcl::getMinMax3D(*pointXYZRBG, min_p, max_p);
double pos_x = (max_p.x - min_p.x) / 2;
double pos_y = (max_p.y - min_p.y) / 2;
double pos_z = max_p.y + 200;
result_viewer->setCameraPosition(pos_x, pos_y, pos_z, pos_x, pos_y, 0.49, 0, 1, 0); //设置相机位置
//这个控制放大
result_viewer->setCameraFieldOfView(0.53299);
result_viewer->setCameraClipDistances(60, 572);
result_viewer->spinOnce();
return 1;
}
catch (...)
{
return 0;
}
}
int PointCloudShowWindows::PCL_Show_InputCloud()
{
try
{
result_viewer->removeAllPointClouds();//将前一次点云移除
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color(Input_cloud, 0, 255, 0);
pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ> fildColor(Input_cloud, "z"); // 按照x字段进行渲染
result_viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample"); // 用于改变显示点云的尺寸。用户可以利用该方法控制点云在视窗中的显示方式。
result_viewer->addPointCloud<pcl::PointXYZ>(Input_cloud, fildColor, "sample"); // 显示点云,其中fildColor为颜色显示
pcl::PointXYZ min_p, max_p; //用于存放三个轴的最小值,最大值
pcl::getMinMax3D(*Input_cloud, min_p, max_p);
double pos_x = (max_p.x - min_p.x) / 2;
double pos_y = (max_p.y - min_p.y) / 2;
double pos_z = max_p.y + 200;
result_viewer->setCameraPosition(pos_x, pos_y, pos_z, pos_x, pos_y, 0.49, 0, 1, 0); //设置相机位置
//这个控制放大
result_viewer->setCameraFieldOfView(0.53299);
result_viewer->setCameraClipDistances(60, 572);
result_viewer->spinOnce();
return 1;
}
catch (...)
{
return 0;
}
}
最终效果就是在系统中选择文件,点击确定可以在 C#中显示点云了
源码链接:https://download.csdn.net/download/qq_43627520/83477939