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

Kinect v2 点云扫描仪和查看器

starIconstarIconstarIconstarIconstarIcon

5.00/5 (11投票s)

2015 年 1 月 14 日

GPL3

8分钟阅读

viewsIcon

68398

downloadIcon

4520

在 OpenGL 控件中显示由 Microsoft Kinect v2 捕获的点云

另请参阅: GitHub 上最新的 代码

引言

本文是我关于使用 Microsoft Kinect v2 抓取点云的文章的续篇。主要功能:

  • 使用 Kinect v2 扫描仪或 Intel Realsense F200 扫描仪抓取点云
  • 在 OpenGL 控件中实时显示点云
  • 可以调整扫描参数,例如最大深度, 扫描到的点云保存为 obj 文件 

    有关 OpenGL 实现的详细信息,请阅读这篇 文章。它使用 OpenTK 库作为 OpenGL 的 C# 接口。

先决条件 

  • Microsoft Kinect SDK v2 
  • .NET 4.6
  • Visual Studio 2015 或更高版本(用于源代码)

 

快速入门

主程序简要说明

  1. 启动程序 PointCloudScanner.exe
  2. 点击“开始扫描” 
  3. 点击“保存点云”以保存并停止扫描

动机

为什么不使用 Kinect SDK 示例

一段时间以来,实际上在我发布本文后,Kinect SDK 示例包含了 Kinect Studio Explorer,它允许在 3D 中实时查看点云。在此之前,只能看到深度、彩色、身体和红外帧的 2D 图像。

但是,Kinect Studio Explorer 仅作为可执行文件提供,不提供源代码,因此您无法在自己的项目中使用它,

提供的源代码可以 3D 查看,并且与 Kinect Explorer 相比具有一些额外功能,例如裁剪抓取的数据等。

为什么是 OpenGL

首先您可能会问:为什么不使用 WPF 窗口显示点云,而是使用我使用的 OpenGL 控件?

嗯,在 WPF 中您无法显示简单的点云。您只能显示表面(或区域、三角形)。因此,您必须首先编写一个三角剖分——这并不容易。

我必须承认:我讨厌 WPF。

WPF 被引入的主要原因有:

  1. UI 和逻辑的分离——原则上允许设计师使用 Blender 设计 UI,程序员使用 Visual Studio 编码。
  2. 支持图形/动画和桌面程序

还有其他原因,如数据绑定、能够在浏览器中运行等,我认为这些原因不太重要。

现在,我讨厌 WPF 的主要原因与上述几点有关:

  1. 更改 UI 非常耗时——例如,为什么我应该使用两个工具来简单地更改 UI??在 WPF 中进行代码更改非常乏味。尝试在 Visual Studio 中打开一个简单的 WPF 控件——显示需要 5 秒以上。出现的消息框说我可以在此期间执行其他任务,这有点可笑。我还想做什么——我只想现在更改代码!
    然后您必须搜索您的控件,找出事件的代码处理程序,然后在您的代码中搜索该方法。大约需要 4 个步骤。使用 Windows Forms,这只需双击即可。
  2. WPF 中的图形支持很差且速度很慢。无法在 WPF 中显示点云。显示大数据速度很慢。

此外,OpenGL 社区庞大,有许多代码技巧和库可以帮助开发。

 

代码

如果您遵循扫描过程,从点击按钮到在 3D 控件中显示数据,则流程是:

1. ScannerUC.StartScanning()
我们使用 Kinect 摄像头,它调用该方法

2. KinectBO.StartScanner()
KinectBO 类封装了 Kinect 执行的所有操作,例如帧捕获、3D 数据转换等。
StartScanner 方法设置用于接收扫描仪数据的委托,并将输出设置为在用户控件上显示数据

3. 扫描仪的每个帧都会调用 KinectBO.Scanner_MultiSourceFrameArrived()。要显示 3D 数据,调用的方法是

4. KinectBO.ProcessDepthFrame() ,然后从这里调用方法

5. KinectBO.UpdateOpenGLControl()
在这里,帧数据在方法中转换为点云

6. KinectBO.ToPointCloudRenderable(false);
这是在以下行中完成的:

7. MetaDataBase.ToPointCloudVertices(this.ColorMetaData, this.DepthMetaData, this.coordinateMapper);
深度帧数据和彩色帧数据由以下方法映射到世界点:

myCoordinateMapper.MapDepthFrameToCameraSpace(myDepthMetaData.FrameData, myRealWorldPoints);

myCoordinateMapper.MapDepthFrameToColorSpace(myDepthMetaData.FrameData, mycolorPointsInDepthSpace);

之后,通过获取深度帧并为方法中的每个像素获取颜色数据来创建点云:

8. MetaDataBasePointCloudVerticesWithColorParallel()
th
在这里我使用了并行化,否则性能会非常低,UI 更新大约每秒一次或更慢。通过使用并行化,性能可达 10 帧/秒。
使用的代码是:

 

private static PointCloud PointCloudWithColorParallel(ColorSpacePoint[] mycolorPointsInDepthSpace, CameraSpacePoint[] myRealWorldPoints, ColorMetaData myColorMetaData, DepthMetaData myDepthMetaData, BodyMetaData myBodyMetaData)
        {

            Vector3[,] arrV= new Vector3[DepthMetaData.XDepthMaxKinect, DepthMetaData.YDepthMaxKinect];
            Vector3[,] arrC = new Vector3[DepthMetaData.XDepthMaxKinect, DepthMetaData.YDepthMaxKinect];

           
            try
            {

                System.Threading.Tasks.Parallel.For(0, DepthMetaData.XDepthMaxKinect, x =>
                {
                    for (int y = 0; y < DepthMetaData.YDepthMaxKinect; y++)
                    {
                        int depthIndex = (y * DepthMetaData.XDepthMaxKinect) + x;

                        if (myDepthMetaData.FrameData[depthIndex] != 0)
                        {
                            if (PointCloudScannerSettings.BackgroundRemoved && myBodyMetaData != null)
                            {
                                byte player = myBodyMetaData.Pixels[depthIndex];
                                if (player != 0xff)
                                {
                                    SetPoint(depthIndex, x, y, arrV, arrC, mycolorPointsInDepthSpace, myRealWorldPoints, myColorMetaData);
                                }

                            }
                            else
                                SetPoint(depthIndex, x, y, arrV, arrC, mycolorPointsInDepthSpace, myRealWorldPoints, myColorMetaData);
                            
        

                        }
                    }
                });

 

然而,颜色映射方法; MapDepthFrameToColorSpace 的行为很奇怪。
-文档说,您应该得到一个“colorpoints”列表,其大小与深度帧相同(即 512*424 = 210788 个点),其中包含颜色信息。colorpoints 包含 x 和 y 坐标,它们应该映射到彩色图像(即从坐标 0,0 到 1920, 1080)。
如果您在调试时检查结果,大多数点都包含负坐标或无穷大值。
好的,您忽略它们(请参阅上面的代码片段,您会检查 x 和 y 坐标是否在边界内)
-但是,结果在物体边缘包含伪影。例如,如果您扫描人脸,您会在边缘看到奇怪的伪影。

我阅读了所有 MS 文档,并在互联网上搜索了已知示例。
由于微软的 Kinect Studio 也不会显示彩色的点云,我认为这是一个已知问题。

单元测试的使用

我花费了大量精力将代码的全部功能都放入单元测试中。某些功能——主要是三角剖分——正在进行中。希望其中一些人能做出贡献来填补空白!只需发送一些代码,我就会将其合并。

要查看示例,您必须先安装 NUnit,然后在 Visual Studio 项目中配置 NUnit exe 的路径,以便运行测试。

提示:我未能使用使用 .NET 2.0 的 NUnit 2.6,但使用 .NET 4.5 编译了 NUnit。NUnit 3.0(alpha 版本)也可能有效——我没有尝试过。

 

例如,打开点云

 

[TestFixture]
[Category("UnitTest")]
public class Example3DModelsFromDisk : TestBase
{
      [Test]
      public void Bunny_obj_Triangulated()
      {
            string fileNameLong = pathUnitTests + "\\Bunny.obj";
            TestForm fOTK = new TestForm();
            fOTK.OpenGL_UControl.LoadModelFromFile(fileNameLong);
            fOTK.ShowDialog();


      }

 

Kinect 项目的类图

这是一个非常粗略的类图,在 Visual Studio 中创建,仅作为概述。但代码层次结构如此简单,以至于不需要复杂的类图:)

 

程序 KinectPointCloud 启动时显示的是“MainWindow”窗体,其中包含用户控件:ScannerUC。此用户控件封装了所有 Kinect 代码。这里有用于开始/停止抓取、构建熵图像、统计显示、在 OpenTK 对话框中打开抓取的点云等的方法。

有两个用于扫描的业务对象,一个用于 Kinect,另一个用于 Intel Real Sense 摄像头。

Intel realsense 的代码尚未准备好,因为我没有使用 Intel 驱动程序,而是尝试连接多个 RealSense 摄像头。这可行,但我没有点云的颜色信息,因为我需要一个颜色和帧数据之间的映射器——而对于映射器,我需要颜色和深度传感器之间的精确校准数据。

Kinect 用户控件的一些重要成员是用于处理 Kinect 抓取数据的类。顾名思义,您可以看到用于处理深度的 DepthMetaData,或用于颜色和身体元数据的类。在这些类中,您可以找到许多(主要是静态的)用于数据处理的方法,例如转换、I/O。

 

OpenTK.Extension 项目的类图

再次,同样的粗略类图

显示的是 OpenGL 用户控件,其中包含一个更基本的用户控件,没有任何组合框等。

此 OpenGL 控件包含 OpenGL 或 OpenGL 的 OpenTK 端口中的所有 3D 处理方法。

执行所有 3D 工作的是 OpenGLContext,它包含 1..n 个 RenderableObject 类型的 3D 对象。它们包含 PointCloud 对象。

 

图像和功能库

1. 斯坦福大学的 3D 小兔子,从不同视角看

 

图像显示(从左到右):点云、线框、实体、凸包线框、凸包实体。
通过加载兔子文件(包含在 bin/TestModels 目录中)然后更改视图模式,您可以获得前三个视图。凸包可以通过使用 NUnit 测试用例来获得。

ConvexHullTest.Bunny_Hull

2. 不同视图下的球体


 

使用的其他代码

我借鉴了其他人的各种代码,这是列表。您也可以在“帮助-关于”窗口中看到列表。


 

注意:此列表是为版本 0.9.0.9 创建的,对于当前版本,还使用了其他源代码,例如:

-KDTree by Matthew B. Kennel,文章:https://arxiv.org/abs/physics/0408067。 C++,Fortran 代码:https://github.com/jmhodges/kdtree2
-KDTree in C# by Jeremy C., https://github.com/Jerdak/KDTree2
-json 库来自: http://www.newtonsoft.com/json

 

关注点

三角剖分应该得到改进,整个部分仍在进行中。
点云对齐是本文最初发布的根本原因。然而,Kinect 扫描的点云似乎不适合对齐——点的质量不够好,并且扫描人脸时,由于最小距离为 0.5 米,点的数量太少。

 

另请参阅

点云查看器文章
点云对齐文章
GitHub 上最新的 代码: 

 

历史

版本 0.9.0.11 于 2017/4/18 - 修复了 UI 和 Kinect 扫描问题
版本 0.9.0.10 于 2017/4/3
版本 0.9.0.9 于 2016/8/14

 

© . All rights reserved.