Kinect v2 点云扫描仪和查看器





5.00/5 (11投票s)
在 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 或更高版本(用于源代码)
快速入门
主程序简要说明
- 启动程序 PointCloudScanner.exe
- 点击“开始扫描”
- 点击“保存点云”以保存并停止扫描
动机
为什么不使用 Kinect SDK 示例
一段时间以来,实际上在我发布本文后,Kinect SDK 示例包含了 Kinect Studio Explorer,它允许在 3D 中实时查看点云。在此之前,只能看到深度、彩色、身体和红外帧的 2D 图像。
但是,Kinect Studio Explorer 仅作为可执行文件提供,不提供源代码,因此您无法在自己的项目中使用它,
提供的源代码可以 3D 查看,并且与 Kinect Explorer 相比具有一些额外功能,例如裁剪抓取的数据等。
为什么是 OpenGL
首先您可能会问:为什么不使用 WPF 窗口显示点云,而是使用我使用的 OpenGL 控件?
嗯,在 WPF 中您无法显示简单的点云。您只能显示表面(或区域、三角形)。因此,您必须首先编写一个三角剖分——这并不容易。
我必须承认:我讨厌 WPF。
WPF 被引入的主要原因有:
- UI 和逻辑的分离——原则上允许设计师使用 Blender 设计 UI,程序员使用 Visual Studio 编码。
- 支持图形/动画和桌面程序
还有其他原因,如数据绑定、能够在浏览器中运行等,我认为这些原因不太重要。
现在,我讨厌 WPF 的主要原因与上述几点有关:
- 更改 UI 非常耗时——例如,为什么我应该使用两个工具来简单地更改 UI??在 WPF 中进行代码更改非常乏味。尝试在 Visual Studio 中打开一个简单的 WPF 控件——显示需要 5 秒以上。出现的消息框说我可以在此期间执行其他任务,这有点可笑。我还想做什么——我只想现在更改代码!
然后您必须搜索您的控件,找出事件的代码处理程序,然后在您的代码中搜索该方法。大约需要 4 个步骤。使用 Windows Forms,这只需双击即可。 - 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 米,点的数量太少。
另请参阅
历史
版本 0.9.0.11 于 2017/4/18 - 修复了 UI 和 Kinect 扫描问题
版本 0.9.0.10 于 2017/4/3
版本 0.9.0.9 于 2016/8/14