65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (25投票s)

2014年11月7日

GPL3

8分钟阅读

viewsIcon

136393

downloadIcon

18209

使用简单的用户控件打开和显示点云。所使用的技术:C# 和通过 OpenTK 移植到 .NET 的 OpenGL 库。

最新代码 github

版本: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 日发布
  - 完全重构:控件现在基于着色器。
  

  

 

© . All rights reserved.