使用 C# 和 OpenGL 的快速点云查看器






4.94/5 (25投票s)
使用简单的用户控件打开和显示点云。所使用的技术:C# 和通过 OpenTK 移植到 .NET 的 OpenGL 库。
版本:0.9.0.9
旧版本:0.9.0.5
引言
您想以很低的开销、用几行代码加载点云吗?
然后对其进行一些数学运算,如特征提取、旋转,或更高级的操作:将点云缝合在一起?
那么您应该继续阅读 :)
背景
我使用 Kinect v2 来提取点云,并且需要一个简单的代码来显示和处理点云。为此,我在网上找不到一个简单的工具。
我尝试使用点云库,但是缺少一个简单的 .NET 接口。在 C++ 中使用它并不容易:编译意味着您需要包含大约一百万个头文件。编译速度慢,而且有很多需要注意的事情,需要阅读很多群组条目,直到它在您的特定系统上运行起来。也许在 Linux 上更容易,但至少在 Windows 64 位上,您需要花一些时间才能让它运行起来。如果您只想加载一个点云并对其进行一些操作,这种开销就很大了。
VTK 库似乎是一个替代方案,但不幸的是,社区不再那么活跃了,所以很少更新,当前版本相当老旧。我还是尝试了一下,请看我 Kinect 文章的链接。在 .NET 中使用 VTK 并不太好,因为 C++ 实现没有很好地封装在 C# 端口(Activiz)中,所以例如您无法很好地在调试器中检查值,或者需要自己负责销毁对象。这些都会减慢您的开发速度。
这只是我尝试中的前两个。
对于第一个发布的版本(参见版本 0.9.0.5),
我发现了一个非常好的 C# 程序,它几乎能完成我想要的一切,来自 Douglas Andrade 在 cmsoft。他允许我采用他的代码并提取其中一部分来用作用户控件。
我就是这样做的,做了些改进,这里有一个您可以在您的项目中使用的小型库。该实用工具使用OpenTK,它封装并扩展了OpenGL。
现在我已经提取了这个用户控件,也许它对其他进行点云处理的人也有用。我认为,许多从事科学 3D 研究的人都对拥有一个简单的库感兴趣。
缺点可能是目前它依赖于 MS Windows 操作系统,但也可以移植到 Mono。
最大的优点是您可以立即开始使用代码,而无需花费数天时间查找依赖项或其他开销,而这是您在使用大多数现有项目时必须做的。
版本 0.9.0.9
然而,对于大量的点,性能并不好,特别是对于实时扫描。
经过完全重构,几乎没有留下原始代码,取而代之的是,我使用了 OpenGL 的着色器技术来实现快速控件。
代码仍在进行中,特别是您会发现许多用于点云配准和对齐的实验性调用。
在某些情况下,程序会因 OpenGL 错误而崩溃 - 我没有调试所有崩溃的原因。
如果您想提供帮助,请进行调查并尝试解决 :)
代码清理也高度必要,仍然存在大量未使用的代码 - 版本 0.9.0.5 的旧的、未使用的代码并未完全从当前版本中清理掉。
我为点云(PointClouds)有重复的类,这也是由于未完成的转换。
改进所有这些对我来说比做一个开源项目还要多,如果有人想帮忙,我会将所有内容移植到 Github,以便进行贡献。
必备组件
Windows 7 或更高版本 64 位
具有 OpenGL 4.0 或更高版本驱动程序的图形适配器
Microsoft .NET 4.6
Microsoft Visual Studio 2013 或更高版本 - 用于源代码
用户控件的特性
有关特性的简要描述,请按照以下步骤操作
1. 启动测试程序 "OpenTKTest"
2. 加载一个点云,例如 bunny.obj 文件,该文件可在源代码和可执行文件分发包的 bin/Model/UnitTests 文件夹中找到。(bunny.obf 文件是斯坦福大学免费提供的点云,在网络上的许多项目中都有使用:链接)。
3. 您可以使用鼠标右键旋转点云,使用鼠标左键平移,使用滚轮缩放。
使用“工具 - 设置”对话框更改模型的颜色或背景等。
在将左上方组合框中的“视图模式”更改为“三角形”后,您会看到类似这样的内容
4. 如果加载多个模型,您可以将一个模型相对于另一个模型在空间中移动。
这是通过以下方式完成的:
- 首先加载两个模型,例如加载 bunny 两次。
- 在“相机/模型”组合框中更改为“模型”。
- 在“选定模型”组合框中更改为第一个模型。
- 现在您可以将第一个模型相对于另一个模型进行旋转/平移/缩放。
请自行尝试进一步的用法,例如更改点的大小等,应该很简单。
编码
用户控件“OpenGLControl”嵌入在测试应用程序的 Windows 窗体中。
您可以简单地将其添加到您自己应用程序的 Windows 窗体中,例如在设计器中。
它包含 OpenTK 库的 GLControl,并扩展了鼠标处理功能,用于旋转、平移、加载文件等。实例化的方式如代码所示。
this.glControl = new OpenTKLib.OGLControl();
用户控件包含 OpenGLContext 类,该类包含控件中使用的所有 3D 数据。
public class OpenGLContext
{
//camera
public Camera Camera;
最重要的成员是包含在变量 List<RenderableObject> RenderableObjects 中的 3D 模型列表。
一个 Renderable Object 包含一个 PointCloud 实例,正如您可以假设的那样,它包含用于绘制的数据。
例如,要加载一个对象文件,您将使用方法
this.PointCloud = PointCloud.FromObjFile(fileName);
OpenGL 中的渲染
控件使用着色器,这是一种非常脆弱的构造。
使用 OpenGL 编程的人会感觉回到了大约 20 年前,介于 C 语言和汇编语言之间。
基本着色器已于 2004 年在 OpenGL 2.0 中引入,但程序员仍未大规模使用它们,大多数代码示例都没有。
着色器的编程甚至比 OpenGL 还要古老,我奇怪为什么没有人将面向对象编程引入 OpenGL。缺乏这一点导致人们进行了大量尝试来寻找 DirectX 等 OpenGL 的替代品。但微软并未成功,主要是因为 OpenGL 是平台无关的,所以我们将不得不与 OpenGL 共存很长一段时间。
着色器提供了更好的性能,所以这样做是值得的。
好的,我改编了一些开源代码,为着色器引入了面向对象。
在 OpenGL 中显示的物体是
RenderableObject,它包含前面提到的 PointCloud 和一个用于着色器的变量。
从用户控件到渲染对象的类图显示如下:
可渲染对象包含点云(一组带有颜色信息、索引等的向量)和一个用于 OpenGL 绘图的着色器。
public abstract class RenderableObject
{
public PointCloud PointCloud = new PointCloud();
public Shader shader = new Shader();
在初始化绘图时,会调用 Shader.InitializeShaders() 方法,该方法加载着色器文件(顶点和片段着色器),然后将它们链接起来,设置属性并生成缓冲区。
public bool InitializeShaders(string filename_vshader, string filename_fshader, string path)
{
try
{
Init();
LoadShaderFromFile(path, filename_vshader, ShaderType.VertexShader);
LoadShaderFromFile(path, filename_fshader, ShaderType.FragmentShader);
Link();
ValidateLink();
SetAttributes();
SetUniforms();
GenBuffers();
}
在绘制 RenderableObject 时,会调用 RenderableObject.Render 方法,该方法将 modelView 矩阵分配给着色器 uniform 地址。
这使得绘制比以前使用着色器更加直接。
public void Render(PrimitiveType myRenderMode, PolygonMode myPolygonMode)
{
RefreshRenderableData();//essential if data has changed after initial call of ActivateShaders
this.shader.Use();
GL.UniformMatrix4(shader.GetUniformAddress("MVP"), false, ref this.mvp);
switch (myRenderMode)
{
case PrimitiveType.Triangles:
{
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
GL.DrawElements(PrimitiveType.Triangles, this.PointCloud.Indices.Length, DrawElementsType.UnsignedInt, 0);
break;
}
快速渲染
如果您想使用实时流式传输到控件(例如在扫描过程中),您可以使用代码
this.openGLControl.GLrender.ReplaceRenderableObject(pcr, false);
这样,在使用大约 100,000 个点的点云时,在“中等”硬件的计算机上(2016 年左右的 800 欧元电脑,总计),您将获得 10-20 帧每秒的更新速率。
一些点云操作的代码示例
1. 创建一个立方体并在窗口中显示它
public void ShowCube()
{
PointCloudVertices cube = PointCloudVertices.CreateCube_Corners(50);
OpenTKForm fOTK = new OpenTKForm();
fOTK.ShowPointCloud(cube);
fOTK.ShowDialog();
}
2. 移动立方体
public void TranslateCube()
{
PointCloudVertices = PointCloudVertices.CreateCube_Corners(50);
PointCloudVertices.Translate(verticesTransformed , 10, 3, 8);
}
3. 旋转点云
PointCloudVertices.RotateDegrees(cube, 25, 10, 25);
4. 缩放点云
Vector3d vScale = new Vector3d(1, 1, 1000);
PointCloudVertices.ScaleByVector(cube, vScale);
5. 不同视图下的 bunny 文件
使用的源代码
使用了各种源代码,请参见列表
关注点
OpenGL 和 OpenTK 是非常强大的工具,OpenTK 的数学库很好。但在进行更复杂的矩阵运算时(这对于图像特征提取或点云拼接是必需的),则需要一些扩展或其他数学库。例如,对于配准,需要奇异值分解。对于迭代最近点算法是必需的。
历史
版本 0.9.0.4 于 2014 年 11 月 7 日发布
版本 0.9.0.5 于 2015 年 1 月 14 日发布
- 更好的旋转、平移、缩放方法
- 增加了许多新的测试用例
-添加了三角剖分方法(进行中)
版本 0.9.0.9 于 2016 年 8 月 14 日发布
- 完全重构:控件现在基于着色器。