c#界面中实现点云动态显示

我在之前的文章中介绍了关于C#界面中实现点云显示的解决方案,整个过程是基于c++开发的动态库实现的。
如果对本文即将介绍的C#实现点云实时显示感兴趣的可以先前往c#系统界面中可视化PCL点云数据简单了解一下实现的流程。

开发工具:PCL C# C++

在使用本文提供的方法前,需要掌握的知识点有:
1、C++ dll动态库的开发
2、PCL点云读取和点云显示
3、C#与C++动态库之间的调用
4、安装好可使用的PCL工具包

需要说明的是本文介绍的内容是将pcl实时显示的功能嵌入c#开发的软件中,相当于是上一篇文章的升级版。

开发流程(思路与上一篇类似)

0、首先系统启动时采用委托自动实例化dll中用于点云显示的模块(将显示位置的句柄传递给pcl显示窗口)
1、c#端选择提前准备好的点云文件(对于实时显示部分,本文是模拟激光雷达的数据。从指定的文件夹中读取提前采集好的数据然后存储起来,使用的时候读取的点云中一次输出)
2、数据读取完后返回存储数据位置的地址,这个地方是方便我们后期可以从C#端直接读取点云
3、实时显示:将数据的地址再次发送到dll中

代码实现

本文同样提供全套的可执行代码
源码地址:https://download.csdn.net/download/qq_43627520/85024460
有咨询方面的需求可通过邮箱与我联系:1499961892@qq.com
效果展示:

c#端


该部分与上一篇文章的差异:
1、增加了实时显示的功能区
2、在文件读取阶段增加了点云文件夹地址提取
委托部分结构没有变化,只是新增了一个句柄

               IntPtr m_hwnd1 = (IntPtr)0;IntPtr m_hwnd2 = (IntPtr)0;// 点云界面初始化if (0 == type){if (pictureBox1.IsHandleCreated == true && pictureBox1.IsHandleCreated == true){m_hwnd1 = pictureBox1.Handle;m_hwnd2 = pictureBox2.Handle;dll_ShowPointCloud.EX_SysInit(m_hwnd1, m_hwnd2); //界面点云显示初始化}}

其中文件读取部分的代码如下:

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;   //获得文件的绝对路径 pcdFile为选定的pcd文件路 也可以是ply文件pcdPath = Path.GetDirectoryName(file.FileName); //获取文件夹的路径 pcdPath是存储点云的文件夹路径Console.WriteLine("Path:" + pcdPath);label1.Text = pcdFile;int res = dll_ShowPointCloud.EX_PointCloud_Init(pcdFile,pcdPath);Console.WriteLine("returnPath:"+ DLL_ShowPointCloud.readFilePtrPath);if (res == 0){label2.Text = "点云读取完毕";}}}catch (Exception ex){MessageBox.Show(ex.Message);}}

点云显示动态库开发

在动态库这块相比于之前发生了一个较大的变化,因为涉及到实时显示,所以对整体实现的过程进行了调整。

动态库的调用接口

#define DLL_API extern"C" _declspec(dllexport)
#include "FlowPCLshow.hpp"
#include "pointProcess.hpp"
#include <boost/thread/thread.hpp># define POINTTYPE pcl::PointXYZIPointCloudProcess<POINTTYPE>* pointCloudProcess = NULL;PointCloudShowWindows<POINTTYPE>* pointCloudShowWindows = NULL;// 定义点云结构体
struct DataPointXYZI
{float x, y, z, i;
}dataPointXYZI;typedef  struct DataPointCloud
{int size = 0;std::vector<DataPointXYZI> data;}dataPointCloud;//设置钩子函数
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<POINTTYPE>::Ptr cloud) {std::string fileType = path.substr(path.find_last_of('.') + 1);//获取文件后缀if (fileType == "ply") {if (pcl::io::loadPLYFile <POINTTYPE>(path, *cloud) == -1){std::cout << "Cloud reading .ply failed." << std::endl;}}else if (fileType == "pcd") {if (pcl::io::loadPCDFile <POINTTYPE>(path, *cloud) == -1){std::cout << "Cloud reading .pcd failed." << std::endl;}}//cout << "point cloud size:" << cloud->size() << endl;
}
//界面初始化
DLL_API int Sys_Init(HWND InitWindow, HWND INPUTWindow) {try {cout << "Sys_Init start" << endl;pointCloudShowWindows = new PointCloudShowWindows<POINTTYPE>();int ShowSR = pointCloudShowWindows->PCL_SHOW_Init((HWND)InitWindow); //初始化结果int input = pointCloudShowWindows->PCL_SHOW_INPUT((HWND)INPUTWindow); //初始化结果cout << "input end" << endl;return input;}catch (...) {return 0;}
}
// 点云显示动态库
DLL_API int PointCloud_Show(int itype) {try {if (1 == itype) {// 显示输入点云pointCloudShowWindows->PCL_Show_InitCloud();}else {//显示彩色点云pointCloudShowWindows->PCL_Show_PointCloud();}return 1;}catch (...) {return 0;}
}
// 设置的全局变量
std::vector<pcl::PointCloud<POINTTYPE>>* p;
pcl::PointCloud<POINTTYPE>::Ptr inputCloud(new pcl::PointCloud<POINTTYPE>);
std::vector<pcl::PointCloud<POINTTYPE>> data_cloud;
std::vector<pcl::PointCloud<POINTTYPE>> cloud_list;
int threadPclShowStop = 1;DLL_API std::vector<pcl::PointCloud<POINTTYPE>>* PointCloud_Init(char* filePathName, char* PathName) {//pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud(new pcl::PointCloud<pcl::PointXYZ>);cout << "filePathName:" << filePathName << endl;loadFile(filePathName, inputCloud);pointCloudShowWindows->PCL_SHOW_WinTypeSet();pointCloudShowWindows->PCL_Updata_InitCloud(inputCloud);data_cloud.push_back(*inputCloud);cout << "filePathName:" << filePathName << endl;pointCloudProcess = new PointCloudProcess<POINTTYPE>();if (PathName != "") {pointCloudProcess->PointCloudList(PathName);cloud_list = pointCloudProcess->pointCloudList;}pointCloudProcess->~PointCloudProcess();p = &cloud_list;cout << "ptr path:" << p << endl;return p;
}
//用于控制点云实时显示的中断过程
DLL_API int Thread_PclShow() {threadPclShowStop = 0;return threadPclShowStop;
}
//读取指定地址中的点云文件进行实时显示
DLL_API int LoadDataFromPtr(std::vector<pcl::PointCloud<POINTTYPE>>* Path) {cout << "LoadDataFromPtr:" << Path << endl;pcl::PointCloud<POINTTYPE> input;std::vector<pcl::PointCloud<POINTTYPE>> data;data = *Path;std::cout << "data size:" << data.size() << endl;threadPclShowStop = 1;int i = 0;while(1){if (threadPclShowStop == 0) {std::cout << "LoadDataFromPtr->input stop!" << endl;break;}input = data.at(i);pointCloudShowWindows->PCL_Updata_InputCloud(input.makeShared());pointCloudShowWindows->input_viewer->spinOnce(100);i++;if (i == data.size()) {//break;i = 0;}}threadPclShowStop = 1;return threadPclShowStop;
}
// 结束时释放点云显示空间
DLL_API int StopAllClass() {pointCloudShowWindows->~PointCloudShowWindows();return 1;
}

上述代码中涉及到的点云读取类 pointCloudProcess 的实现过程如下:


template<typename PointT>
PointCloudProcess<PointT>::PointCloudProcess()
{
}template<typename PointT>
PointCloudProcess<PointT>::~PointCloudProcess()
{
}
template<typename PointT>
typename pcl::PointCloud<PointT>::Ptr PointCloudProcess<PointT>::load_File(std::string filePath) {typename pcl::PointCloud<PointT>::Ptr cloud(new typename pcl::PointCloud<PointT>);std::string fileType = filePath.substr(filePath.find_last_of('.') + 1);//获取文件后缀if (fileType == "ply") {if (pcl::io::loadPLYFile <PointT>(filePath, *cloud) == -1){std::cout << "Cloud reading .ply failed." << std::endl;}}else if (fileType == "pcd") {if (pcl::io::loadPCDFile <PointT>(filePath, *cloud) == -1){std::cout << "Cloud reading .pcd failed." << std::endl;}}cout << "point cloud size:" << cloud->size() << endl;return cloud;
}
//获取所有的数据
template<typename PointT>
std::vector<typename pcl::PointCloud<PointT>> PointCloudProcess<PointT>::PointCloudList(std::string dataPath)
{std::vector<std::string> pathList = getFilesList(dataPath);typename pcl::PointCloud<PointT>::Ptr loadCloud(new typename pcl::PointCloud<PointT>);for (int i = 0; i < pathList.size(); i++) {std ::string file = pathList[i];loadCloud = load_File(file);pointCloudList.push_back(*loadCloud);}return pointCloudList;
}
/** 读取文件夹数据*/
template<typename PointT>
std::vector<std::string> PointCloudProcess<PointT>::getFilesList(std::string Path) {std::string PathList = Path + "/*.*";std::vector<std::string> allFilePath;intptr_t handle;_finddata_t findData;handle = _findfirst(PathList.c_str(), &findData);//检测是否成功if (handle == -1) {cout << "can not found the file ... " << endl;return allFilePath;}do{if (findData.attrib & _A_SUBDIR) //是否含有子目录{//若该子目录为"."或"..",则进行下一次循环,否则输出子目录名,并进入下一次搜索if (strcmp(findData.name, ".") == 0 || strcmp(findData.name, "..") == 0)continue;// 在目录后面加上"\\"和搜索到的目录名进行下一次搜索std::string dirNew = Path + "/" + findData.name;std::vector<std::string> tempPath = getFilesList(dirNew);allFilePath.insert(allFilePath.end(), tempPath.begin(), tempPath.end());}else //不是子目录,即是文件,则输出文件名和文件的大小{std::string filePath = Path + "/" + findData.name;allFilePath.push_back(filePath);cout << filePath << "\t" << findData.size << " bytes.\n";}} while (_findnext(handle, &findData) == 0);return allFilePath;
}

为了使我们写的函数可以适用于不同数据类型的点云(xyz,xyzi,xyzrgb),我们使用了template<typename PointT>来定义类中点云的数据类型

点云显示

在上一篇文章的基础上新增了一个点云初始化的窗口

// 用于更新实时显示的点云
template<typename PointT>
int PointCloudShowWindows<PointT>::PCL_Updata_InputCloud(typename pcl::PointCloud<PointT>::Ptr Cloud) {Input_cloud.reset(new typename pcl::PointCloud<PointT>);Input_cloud->resize(Cloud->size());Input_cloud = Cloud;pcl::visualization::PointCloudColorHandlerGenericField<PointT> fildColor(Input_cloud, "z"); // 按照x字段进行渲染input_viewer->removeAllPointClouds();input_viewer->addPointCloud<PointT>(Input_cloud, fildColor, "sample"); // 显示点云,其中fildColor为颜色显示return 0;
}
//初始化实时显示点云的窗口
template<typename PointT>
int PointCloudShowWindows<PointT>::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(0, 0, 0);//设置背景颜色input_viewer->initCameraParameters();//初始化相机的参数input_viewer_win = input_viewer->getRenderWindow();//将view中的渲染窗口的句柄传递给vtk windowinput_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;}}template<typename PointT>
int PointCloudShowWindows<PointT>::PCL_SHOW_WinTypeSet() {Init_viewer->setCameraPosition(11.6749, 17.4117, 27.2977, -0.404992, -0.6874, 0.602879);Init_viewer->setCameraClipDistances(0.160147, 160.147);input_viewer->setCameraPosition(11.6749, 17.4117, 27.2977, -0.404992, -0.6874, 0.602879);input_viewer->setCameraClipDistances(0.160147, 160.147);return 0;
}
template<typename PointT>
int PointCloudShowWindows<PointT>::PCL_Show_InitCloud()
{try{Init_viewer->removeAllPointClouds();//将前一次点云移除pcl::visualization::PointCloudColorHandlerGenericField<PointT> fildColor(Init_cloud, "z"); // 按照x字段进行渲染Init_viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample"); // 用于改变显示点云的尺寸。用户可以利用该方法控制点云在视窗中的显示方式。Init_viewer->addPointCloud<PointT>(Init_cloud, fildColor, "sample"); // 显示点云,其中fildColor为颜色显示Init_viewer->spinOnce();return 1;}catch (...){return 0;}
}

最终效果

C#窗体实时显示点云

c#界面中实现点云动态显示相关推荐

  1. 百度云同盘在计算机显示不出来的,wps网盘图标消失了如何让其显示在“我的电脑”界面中...

    wps网盘图标消失了如何让其显示在"我的电脑"界面中 不知道大家有没有遇到过明明安装了wps却没显示器图标的情况,今天小编就告诉大家wps网盘图标消失了如何让其显示在"我 ...

  2. 禾赛40M如何成功在rviz中显示点云数据

    禾赛40M如何成功在rviz中显示点云数据 文章目录 禾赛40M如何成功在rviz中显示点云数据 前言 一.安装雷达的ROS驱动包 二.启动雷达 三.启动rviz查看点云 1.启动launch文件与r ...

  3. pycharm中配置华为云服务器

    之前上课老师给了华为云的代金券,实在用不惯网页版的python编辑器,而且文件同步很麻烦,检索全网也没有怎么将华为云服务器配置到pycharm的说明.于是,摸索了一会,记录下配置流程,供大家参考使用. ...

  4. 部署CentOS可视化界面GUI-之腾讯云服务器

    目录 一.购买云服务器实例 二.配置安全组.设置管理员密码 三.远程登录 四.安装CentOS可视化界面GUI 4.1.系统GUI配置 4.2.系统GUI配置 五.GUI或Console之间的界面切换 ...

  5. [施工中]Java阿里云服务器ECS建站操作不完全指北

    [施工中]Java阿里云服务器ECS建站操作不完全指北 ECS建站操作记录 前言 一 .Xshell6与Xftp6 1.1Xshell与Xftp的作用 1.2如何从官网下载xshell与xftp 1. ...

  6. 怎样在计算机里恢复云文档图标,电脑常识科普:Win10资源管理器中的WPS云文档图标怎么彻底删除...

    如今我们的生活当中不仅仅是办公会实用到电脑,我们日常当中很多时候都需要电脑来帮助我们解决一些问题,那么在使用电脑的时候肯定就会遇到各种各样的问题,那么我们应该怎么去解决这些问题呢?那么这个时候我们就需 ...

  7. 整合Tkinter GUI界面的古诗词词云生成

    Python语言提供的wordcloud词云功能,使文本数据的可视化,简单而美丽.但网上的大多数词云生成功能,多半没有可交互的GUI界面,使用起来稍觉不便.笔者结合网上的中文词云功能,以唐诗三百首,宋 ...

  8. 关于在python的tkinter界面中镶嵌mayplotlib动态图

    关于在python的tkinter界面中镶嵌mayplotlib动态图 很多的时候,我们需要给客户展示一些比较美观的界面,中间就必然需要一些精美的图表,让客户看起来更加的专业,因此,我们就需要tkin ...

  9. Gox语言中进行屏幕截图并显示在Sciter图形界面中-GX38.2

    本例承接GX38.1一文中的例子,加了一些改进,在进行界面截图后,将图片展示在用Sciter包编写的图形界面上. 代码如下: // 设置github.com/kbinani/screenshot包的简 ...

最新文章

  1. Insert Interval
  2. golang goroutine的调度模型:MPG模式
  3. AI产业化应用落地,飞桨三大服务平台帮你开启加速模式
  4. java数据类型及其说明
  5. c++ winpcap开发(8)
  6. .Net的 Web项目的打包过程
  7. 问题记录——sqlserver视图重命名的陷阱
  8. SSL 3.0曝出Poodle漏洞的解决方案-----开发者篇(转自:http://blog.csdn.net/lyq8479/article/details/40709175)...
  9. SQL 2005数据库函数基本应用
  10. UVA722 LA5359 Lakes【DFS】
  11. 如何自定义安装mysql_安装MySQL
  12. Landsat8—ANG.txt文件
  13. geotoolkit 测井曲线显示时间、深度双刻度
  14. 如何识别服务器网站有病毒,网站有病毒怎么解决?
  15. Tableau安装详解及密钥申请
  16. c#中regex的命名空间_C# Regex类用法
  17. R实战 | 环状热图(circos)
  18. 夜神模拟器adb连接电脑
  19. 2022年贵州二级建造师建设工程法规及相关知识模拟题及答案
  20. JAVA团队开发手册 - 1.环境搭建

热门文章

  1. Proteus创建新项目的详细操作步骤(keil和Proteus联合仿真)
  2. Subsonic中使用事务
  3. (转)UltraEdit 注册机使用激活方法
  4. 单片机+人体红外感应的自动垃圾桶源程序与原理图
  5. 基于微信小程序云开发(校园许愿墙app)妄想替代学校的表白墙
  6. 新手入坑编程语言kotlin开局介绍篇
  7. 好机会!IT工程师恭喜了!纳入工信部-工业互联网人才库!8月31日报名截止
  8. 大整理!程序员最爱的12个免费Python课程
  9. 有史以来关于Flash Player的最详细说明
  10. js常见的的6种继承方式