游戏蛮牛学习群(纯技术交流,不闲聊):539178957
游戏蛮牛 手机端
开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

首页   >   博客   >   刘彦磊

获取kinectv2 的深度图,并且分析数据,将深度图按不同深度转换彩色数据。 ... ... 热度 17

个人分类: Unity +Kinect | 2017-3-15 16:20
9 个评论 | 阅读 3578 | 收藏 | 举报
环境Unity 5.4.3 Kinect sdk 2.0  为啥 我这里要说 明开发环境, 就是以前遇到有的人 胡乱在网上复制掉代码,导致我用不同版本开发,总是一堆错误。 但是还不知道为啥。 这里特此声明。

先说下思路吧。  如果想看懂这篇文章,那么请看下 kinect的知识,因为如果没有这些知识,很难看懂。 高手 忽略。 

Unity 的kinect sdk  已经有获取的 深度图像的api 了,所以这款很方便,那么我们怎么把 获取的深度图按照深度来染色?? 。 首先我们要知道,kinect摄像头获取的深度图视频流, 我们可以一帧帧的处理, 你可以理解一帧其实就是一张图片。jpg,png 都可以, 然后 我们获取每一个像素点的 深度值信息, 根据深度值大小 设置不同颜色。就好了。 
上代码。
这个类是获取 深度图像的类

[code]csharpcode:

using UnityEngine;
using System.Collections;
using Windows.Kinect;

public class DepthSourceManager: MonoBehaviour
{   
    private KinectSensor _Sensor;  // 传感器实例
    private DepthFrameReader _Reader;// 深度图读取器
    private ushort[] _Data; //深度数据值

    public ushort[] GetData()
    {
        return _Data;
    }

    void Start () 
    {
        _Sensor = KinectSensor.GetDefault(); //获取默认的传感器。
        
        if (_Sensor != null) 
        {
            _Reader = _Sensor.DepthFrameSource.OpenReader(); //开启深度数据流
            _Data = new ushort[_Sensor.DepthFrameSource.FrameDescription.LengthInPixels]; // 开辟空间。根据深度信息的大小
        }
    }
    
    void Update () 
    {
        if (_Reader != null)
        {
            var frame = _Reader.AcquireLatestFrame(); //获取深度数据流
            if (frame != null)
            {
                frame.CopyFrameDataToArray(_Data); //把深度信息拷贝到数组。
                frame.Dispose();
                frame = null;
            }
        }
    }
    
    void OnApplicationQuit()
    {
        if (_Reader != null)
        {
            _Reader.Dispose();
            _Reader = null;
        }
        
        if (_Sensor != null)
        {
            if (_Sensor.IsOpen)
            {
                _Sensor.Close();
            }
            
            _Sensor = null;
        }
    }
}
这样,我们就把 深度图像帧 里面所有信息 保持到了 _Data 这个数组。 那么就拿这个数组开到,看看里面又啥

[code]csharpcode:

using UnityEngine;
using System.Collections;
using Windows.Kinect;
using System;
using UnityEngine.UI;

public class DepthSourceView1 : MonoBehaviour
{
    public GameObject DepthSourceManager;  //这个其实就为了获取 上面脚本。我们把上面脚本挂到一个物体,然后把物体赋值给这个变量。
    private KinectSensor _Sensor;
    private DepthSourceManager _DepthManager;
    private FrameDescription depthDescription;
    private Texture2D depthBitmap;  //要显示图片。


    ushort[] pixelData;
    Int32 depth;
    Int32 loThreshold = 50;  //最近能测距离50mm  //这里面可以自己定义。
    Int32 hiThreshold = 450;  //最远能测距离450mm
    Int32 bytesPerPixel = 4;  //32位彩色图像,4字节
    Color[] enhPixelData;  //用于保存彩色图像的数据
    private int xxx = 0;
    void Awake()
    {

    }
    void Start()
    {
        _Sensor = KinectSensor.GetDefault();
        depthDescription = _Sensor.DepthFrameSource.FrameDescription;

        //初始化保持彩色图像数据的大小
        enhPixelData = new Color[depthDescription.Width * depthDescription.Height];
        depthBitmap = new Texture2D(depthDescription.Width, depthDescription.Height);
        if (_Sensor != null)
        {
            if (!_Sensor.IsOpen)
            {
                //存放深度图像的字节数组的长度=帧长度*帧高度
                pixelData = new ushort[depthDescription.LengthInPixels];
                _Sensor.Open();
            }
        }
    }
    void Update()
    {
        if (_Sensor == null)
        {
            return;
        }
        if (DepthSourceManager == null)
        {
            return;
        }

        _DepthManager = DepthSourceManager.GetComponent<DepthSourceManager>();
        if (_DepthManager == null)
        {
            return;
        }
        RefreshData(_DepthManager.GetData());
    }


    //获取到每个像素的深度值
    private void RefreshData(ushort[] depthData)
    {
        DepthToColorImage(ref depthData);

    }

    private void DepthToColorImage(ref ushort[] pixelData)
    {
        //获取每一像素的深度值。
        //这里建立一个数组 专用来存color32颜色。 然后用 Texture2d.SetPiels(Color32[]) 生成图片
        for (int i = 0; i < pixelData.Length; i++)
        {
            depth = pixelData[i] >> 3;  //深度帧每个数据的后三位保存这个帧数据的深度值大小。
            //if (xxx ==0)
            //{
            //    Debug.Log("depth value:" + depth);

            //}
            if (depth < loThreshold)
            {
                enhPixelData[i].r = 0;
                enhPixelData[i].g = 0;
                enhPixelData[i].b = 0;

            }
            else if (depth > hiThreshold)
            {
                enhPixelData[i].r = 0;
                enhPixelData[i].g = 0;
                enhPixelData[i].b = 1;
            }
            else if (depth > loThreshold && depth < 100)
            {
                enhPixelData[i].r = 0.5f;
                enhPixelData[i].g = 0;
                enhPixelData[i].b = 0;

            }
            else if (depth > 100 && depth < 200)
            {
                enhPixelData[i].r = 1;
                enhPixelData[i].g = 0;
                enhPixelData[i].b = 0;
            }
            else if (depth > 200 && depth < 250)
            {
                enhPixelData[i].r = 0;
                enhPixelData[i].g = 0.5f;
                enhPixelData[i].b = 0;
            }
            else if (depth > 250 && depth < 300)
            {
                enhPixelData[i].r = 0;
                enhPixelData[i].g = 1;
                enhPixelData[i].b = 0;
            }
            else if (depth > 300 && depth < 350)
            {
                enhPixelData[i].r = 0;
                enhPixelData[i].g = 0;
                enhPixelData[i].b = 0.5f;
            }
            else
            {
                enhPixelData[i].r = 0;
                enhPixelData[i].g = 0;
                enhPixelData[i].b = 1;
            }

        }
        depthBitmap.SetPixels(enhPixelData);
        depthBitmap.Apply();

        gameObject.GetComponent<Renderer>().material.mainTexture = depthBitmap;
    }

    private void ConvertHslToRgb(Double hue, Double saturation, Double lightness, byte[] rgb)
    {
        Double red = 0.0;
        Double green = 0.0;
        Double blue = 0.0;
        hue = hue % 360.0;
        saturation = saturation / 100.0;
        lightness = lightness / 100.0;
        if (saturation == 0.0)
        { red = lightness; green = lightness; blue = lightness; }
        else
        {
            Double huePrime = hue / 60.0;
            Int32 x = (Int32)huePrime;
            Double xPrime = huePrime - (Double)x;
            Double L0 = lightness * (1.0 - saturation);
            Double L1 = lightness * (1.0 - (saturation * xPrime));
            Double L2 = lightness * (1.0 - (saturation * (1.0 - xPrime)));

            switch (x)
            {
                case 0: red = lightness; green = L2; blue = L0; break;
                case 1: red = L1; green = lightness; blue = L0; break;
                case 2: red = L0; green = lightness; blue = L2; break;
                case 3: red = L0; green = L1; blue = lightness; break;
                case 4: red = L2; green = L0; blue = lightness; break;
                case 5: red = lightness; green = L0; blue = L1; break;
            }
        }
        rgb[0] = (byte)(255.0 * red);
        rgb[1] = (byte)(255.0 * green);
        rgb[2] = (byte)(255.0 * blue);
    }

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

            _Sensor = null;
        }
    }

    void OnGUI()
    {

        GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), depthBitmap, ScaleMode.StretchToFill);

    }
}

这里再说一次,  一定要明白 texture2d 的数据结构, 和 深度帧每一个帧数据结构, 将他们结构一一对应,这样就可以实现转换了。 然后我们把这个 texture2d 作为纹理给plane, 这样就可以显示了。

15 0

评论 (9 个评论)

回复 走在海边 2017-4-20 11:14
具体怎么个用法呢,弄了好几次都不行啊。
MissingComponentException: There is no 'Renderer' attached to the &quot;RawImage&quot; game object, but a script is trying to access it.
You probably need to add a Renderer to the game object &quot;RawImage&quot;. Or your script needs to check if the component is attached before using it.
DepthSourceView1.DepthToColorImage (System.UInt16[]& pixelData) (at Assets/KinectDemos/Test2/DepthSourceView1.cs:138)
原来是没用plane
即使这样也不能在game中看到啊,场景中plane中可以看到
DepthSourceView1.RefreshData (System.UInt16[] depthData) (at Assets/KinectDemos/Test2/DepthSourceView1.cs:68)
DepthSourceView1.Update () (at Assets/KinectDemos/Test2/DepthSourceView1.cs:62)
不知道什么意思
回复 走在海边 2017-4-20 16:48
我自己解决问题了,你的代码是有问题的,alpha的值没有设置,默认为0.
回复 走在海边 2017-4-26 21:25
有问题啊。显示不出来。
回复 梦回环 2017-6-12 19:48
ddhg;dh;gyh;dlfyhg;dkf;g
回复 仅有的习惯 2017-7-3 16:46
请问深度图显示了~怎么优化那些噪点。
回复 仅有的习惯 2017-7-3 16:48
请问深度图的噪点怎么去除?0-0
回复 zx1505094452 2017-10-10 21:56
谢谢大佬,刚弄这个没头绪,看到了你的教程,谢谢了
回复 zx1505094452 2017-10-11 20:23
大佬请问我想据不同的深度去投影不同的画面,也是同样的原理吗?可以给每一个像素赋值颜色,但是不可以给每一个像素赋值贴图啊,,,求解大佬
回复 似水彪心 2017-10-24 21:57
感觉右移3位不能正确对应到现实的距离

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册帐号

个人分类

标签

阅读排行

评论排行

推荐博客

最新博客

返回顶部