c#界面中显示PCL点云数据

c#窗体界面显示点云图像

问题描述:我们在开发有关pcl点云系统的时候,通常会遇到的问题就是如何将pcl、c++读取的点云数据或点云图像可视化到提前写好C#界面中。(不是显示到pcl自带的点云可视化窗口中)

开发工具:C++、PCL、C#

在学习本文之前需要掌握一下知识点:
1、C++ dll动态库的开发
2、PCL点云读取和点云显示
3、C#与C++动态库之间的调用

C#实现PCL点云数据可视化的流程

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
有咨询方面的需求也可通过邮箱与我联系:1499961892@qq.com

C#端代码

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);
     }
 }

c++编译的动态库

#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;
}

PclShow.h头文件

#pragma once

#include <time.h>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include <string>
#include <pcl\filters\extract_indices.h>
#include <pcl/io/ply_io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h> 
#include <pcl/visualization/cloud_viewer.h> 
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <pcl/common/common.h>

//钩子函数
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;
};

C++写好的基于PCL的点云可视化类

#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

  • 6
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LuLaDe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值