kinect获取深度数据并显示

在上述深度帧获取的基础上,利用unity的Mesh组件,将深度帧显示出来。

工具为Unity5.6、Kinect开发包KinectForWindows_UnityPro_2.0.1410

首先讲一个Mesh的应用

Mesh有多种方式实现,这里只用最简单的,通过设定顶点组成三角形集合的方式,主要工作是设定三个属性:

①  vertices,顶点集合,Vector3类型,一般为所要显示的像素坐标集合,这里为深度帧每个像素的坐标值,其中z为深度值。

注意:Unity中顶点数量不能超过65000个。

②uv ,UV集合,Vector2类型,

③triangles,三角形所含顶点索引集合,int类型。在由三个顶点组合时,索引的顺序必须按照顺时针存储。

假设现有4个顶点 上左(1)上右(2)下左(3)下右(4),括号内位索引,则三角形1的存放顺序为1、2、3,三角形2的存放顺序为3、1、4。

基本实现思路是:

①根据深度帧的大小和采样频率,创建一个Mesh,为什么需要采样,因为顶点数不能太多,这时Mesh中的属性除了顶点的z坐标未确定外,其余都已经OK。

②获取深度帧,找到Mesh中每个顶点所对应的像素点,就找到了该顶点的深度值,这时z坐标也确定了,刷新,完成。

下面开始上代码:

1 定义变量

    private KinectSensor _Sensor;  //Kincet传感器
    private DepthFrameReader _depthReader; //深度帧读取器
    private ushort[] _depthData; //因为深度数据为2字节16bit,所以定为ushort存放数据
    private Mesh _Mesh;
    //顶点集合
    private Vector3[] _Vertices;
    //顶点的UV坐标集合
    private Vector2[] _UV;
    //三角形的顶点集合,_Vertices中的
    private int[] _Triangles;
    //only works at 4 right now
    //降频采样大小
    private const int _DownsampleSize = 4;
    //实际距离与Unity内模型距离的缩放系数,若实际距离为4m,则在Unity中显示为0.04m
    private const float _DepthScale = 0.01f;

2.初始化

    void Start () {
        _Sensor = KinectSensor.GetDefault ();
        if (_Sensor != null) {
            _depthReader = _Sensor.DepthFrameSource.OpenReader ();
            var frameDescript = _Sensor.DepthFrameSource.FrameDescription;
            //数组大小为整个像素的长度
            _depthData = new ushort[frameDescript.LengthInPixels];
            //创建Mesh网格  还差顶点的z值 即深度值,为了减少顶点数量 所以进行采样。
            CreateMesh (frameDescript.Width / _DownsampleSize, frameDescript.Height / _DownsampleSize);

        }
        if (!_Sensor.IsOpen)
            _Sensor.Open ();
    }

3.创建Mesh网格,网格中顶点的数量为像素点的数量,width*height

void CreateMesh(int width,int height)
    {
        _Mesh = new Mesh ();
        GetComponent<MeshFilter> ().mesh = _Mesh;
        _Vertices = new Vector3[width * height];
        _UV = new Vector2[width * height];
        //三角形的数量等于横竖像素点减1“-1”后相乘 再乘以6 如下:
        _Triangles = new int[(width - 1) * (height - 1) * 6]; 

        int triangleIndex = 0;
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                //顶点的索引就是像素按照一行一行的记录,坐标值x,y为像素在平面的位置,z为深度值
                int index = y * width + x;
                _Vertices [index] = new Vector3 (x, -y, 0);
                _UV [index] = new Vector2((float)x /width, (float)y /height);

                //确定三角形的顶点索引,每四个顶点确定两个三角形,每个三角形的顶点索引顺序为顺时针,否则不予显示
                //忽略最后一行和列,
                if (x != (width - 1) && y != (height - 1)) {
                    int top_left = index;
                    int top_right = top_left + 1;
                    int bottom_left = top_left + width;
                    int bottom_right = bottom_left + 1;
                    //第一个三角形
                    _Triangles [triangleIndex++] = top_left;
                    _Triangles [triangleIndex++] = top_right;
                    _Triangles [triangleIndex++] = bottom_left;
                    //第二个三角形
                    _Triangles [triangleIndex++] = bottom_left;
                    _Triangles [triangleIndex++] = top_right;
                    _Triangles [triangleIndex++] = bottom_right;
                }
            }
        }
        _Mesh.vertices = _Vertices;
        _Mesh.uv = _UV;
        _Mesh.triangles = _Triangles;
        _Mesh.RecalculateNormals ();

    }

4获取深度值后,通过将深度数据赋予对应的顶点,显示深度图

    //将深度数据赋予对应的顶点,显示深度帧数据,
    void ShowDepthView()
    {
        var frameDescript = _Sensor.DepthFrameSource.FrameDescription;
        //这里的x,y是没有采样的像素点,所以需要加采样频率才能和采样过的顶点集合想对应,x,y主要用来计算采样点和周围点的平均深度值
        for (int y = 0; y < frameDescript.Height; y += _DownsampleSize) {
            for (int x = 0; x < frameDescript.Width; x += _DownsampleSize) {
                int indexX = x / _DownsampleSize;
                int indexY = y / _DownsampleSize;
                int smallIndex = (indexY*(frameDescript.Width/_DownsampleSize)) + indexX;
                //计算平均深度值
                float avg = GetAvgDepth (x, y, frameDescript.Width, frameDescript.Height);
                _Vertices [smallIndex].z = avg * _DepthScale;
            }
        }
        _Mesh.vertices = _Vertices;
        _Mesh.uv = _UV;
        _Mesh.triangles = _Triangles;
        _Mesh.RecalculateNormals ();
    }
    float GetAvgDepth(int x,int y,int width,int height)
    {//计算平均深度值
        double sum = 0;
        for (int y1 = y; y1 < y + _DownsampleSize; y1++) {
            for (int x1 = x; x1 < x + _DownsampleSize; x1++) {
                int index = y1 * width + x1;
                if (_depthData [index] == 0)
                    sum += 4500;//表示超出范围
                else
                    sum += _depthData [index];
            }
        }
        int count = _DownsampleSize * _DownsampleSize;
        return (float)(sum/count);
    }

5 获取深度数据,并显示

    void Update () {
        if (_depthReader == null)
            return;
        var frame = _depthReader.AcquireLatestFrame ();
        if (frame != null) {
            frame.CopyFrameDataToArray (_depthData);

            ShowDepthView ();
            frame.Dispose ();
            frame = null;
        }
    }

6 释放

    void OnApplicationQuit()
    {
        if (_depthReader != null) {
            _depthReader.Dispose ();
            _depthReader = null;
        }
        if (_Sensor != null) {
            if (_Sensor.IsOpen) {
                _Sensor.Close ();
            }
            _Sensor = null;

        }
    }

7效果,当取样频率为4时

时间: 2024-12-28 03:06:34

kinect获取深度数据并显示的相关文章

android 从服务器获取新闻数据并显示在客户端

新闻客户端案例 第一次进入新闻客户端需要请求服务器获取新闻数据,做listview的展示, 为了第二次再次打开新闻客户端时能快速显示新闻,需要将数据缓存到数据库中,下次打开可以直接去数据库中获取新闻直接做展示. 总体步骤: 1.写布局listview ok 2.找到listview,设置条目的点击事件. ok 3.获取数据提供给listview做展示. 3.1:获取本地数据库缓存的新闻数据,让listview显示.如果没有网络不至于显示空界面. 3.2:请求服务器获取新闻数据,是一个json字符

使用 Qt 获取 UDP 数据并显示成图片

一个项目,要接收 UDP 数据包,解析并获取其中的数据,主要根据解析出来的行号和序号将数据拼接起来,然后将拼接起来的数据(最重要的数据是 R.G.B 三个通道的像素值)显示在窗口中.考虑到每秒钟要接收的数据包的数量较大,Python 的处理速度可能没有那么快,而且之前对 Qt 也比较熟悉了,所以用Qt 作为客户端接收处理数据包,用近期学习的 Python 模拟发送数据包. 数据格式 在 TCP/IP 协议中,UDP 数据包的大小是由限制的,因此用 UDP 传输数据时,还要在 UDP 层上再封装一

创建一个Java Web项目,获取POST数据并显示

新建一个新的Java Web工程项目 打开IntelliJ IDEA 新建一个工程,选择选择Java Enterprise,设置Tomcat的安装目录,点击下一步. 选中Create project from template,点击下一步: 创建工程成功,可以看到目录结构是如下图一样的: 第一个程序,HelloWorld程序 JSP代码要使用<%%>包起来,因此HelloWorld输出到网页上是这么写的: 变量的使用 Java Web中的变量是这么声明和使用的. 构建一个登录页面 接受表单参数

Kinect 2.0 + OpenCV 显示深度数据、骨架信息、手势状态和人物二值图

1.前言 Kinect 2.0实测比第一代性能提升非常多! 本来想简单地找个教程复制黏贴一下,居然还没有人写过C++版的Kinect 2.0教程,自己摸索了一下,现在把结果拿出来和大家分享. 实现的功能是:深度数据(Depth Data),骨架信息(Body Data),手势状态(Hand State)和人物二值图(就是图1的那个东西,微软官方称法是Body Index Data)的提取和显示. 效果如下: 图1 骨架信息,人物二值图和手势状态 图2 深度信息 2.安装 Kinect 2.0的安

Kinect 开发 &mdash;&mdash; 骨骼数据与彩色影像和深度影像的对齐

在显示彩色影像和深度影像时最好使用WriteableBitmap对象: 要想将骨骼数据影像和深度影像,或者彩色影像叠加到一起,首先要确定深度影像的分辨率和大小,为了方便,这里将深度影像数据和彩色影像数据都采用640x480Fps30的格式,同时将Grid的大小也设置为640*480. 要将骨骼数据和深度影像数据叠加,需要将关节点转换到深度影像所在空间中,可以直接调用MapSkeletonPointToDepthPoint,如果要将骨骼数据叠加到彩色影像上,只需要调用MapSkeletonPoin

kinect学习笔记(三)&mdash;&mdash;深度数据的提取

一.创建Console工程 二.添加kinect引用 里面用引用,打开后 选择然后OK. 三.编写代码(有附加注释) using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Kinect; namespace DepthCout { class Program { static void M

如何不显示地图就获取位置数据?

使用“同步加载插件的方式”,引用各类插件,就可以不创建地图,直接获取地图数据. 以下用IP定位做为例子,详细讲述“如何不显示地图就获取当前位置”. 引入城市定位插件,更多插件与使用方法请见插件类总览 <script type="text/javascript" src="http://webapi.amap.com/maps?v=1.3&key=您的Key&plugin=AMap.CitySearch"></script> 实

Jquert data方法获取不到数据,显示为undefined。

在使用jquery的data-xxxx自定义属性名使用小写 以下是我测试代码: 结果显示Undefined 现在将"data-Name"变为"data-name",将大写的部分全部变为小写. 可以获取到数据 结果: 下面再给大家一些链接关于jquery的attr,data和prop的区别,由于别人写的挺详细的我这边就不再写了. http://www.cnblogs.com/yaomeng/p/5359894.html 这边提醒一下,使用jquery的data更新数据

获取datagrid选中行的数据,显示到window窗口中

(在上次随笔代码的基础上) 1.datagrid代码: <div style="width:100%;height:100%;">    <table class="easyui-datagrid" id="datagridUser" style="width: 100%; height: 95%;" data-options="singleSelect:true,url:'@Url.Action(