牛骨文教育服务平台(让学习变的简单)
博文笔记

Intel RealSense开发一

创建时间:2017-06-02 投稿人: 浏览次数:3585

更新: 通过一位同事的对比校验,在重装了驱动和SDK后一切正常,F200的案例都可以正常运行了,而我俩的操作区别仅在于,我在安装SDK完成后没有重启电脑!由此浪费了大量精力,无话可说….
更新: 后续研究中发现了不少问题,SDK版本问题不说了,R3已经不支持R200,R2版本中UnityToolkit中的例子都无法使用,解决的过程中发现不仅有特性支持的问题,代码问题,还有Unity官方bug的问题,另本篇描述的过程在之后也是时灵时不灵,最后发现只要涉及深度数据的获取,不论是这里的代码还是UnityToolkit中的代码都会有问题,最后建议各位,如果做RealSense的开发,还是别用R200了,当然我只是站在我的技术水平上做的建议,大牛请忽略。
另外列出过程中遇到的问题的参考链接:
解决EnsureRunningOnMainThread报错;
解决unable to initialize all modalities报错;
解决rendererupdatemanager.updateall报错;


对于一个菜鸟程序员来说,入手RealSense开发真不是一件轻松的事。网上关于这方面的开发文章偏少,且只记录了重点,细节没有,官方Demo也不够“贴心”,好在经历一番曲折之后,成功实现了彩色图像和深度图像的抓取,特此记录,以供大家参考。由于水平所限,不对代码含义进行解读,请见谅。


开发环境

摄像头: Intel RealSense R200
CPU: Intel Core I7 7700K
GPU: GeForce GTX 1070
软件: Win10 + Visual Studio 2015 + Unity 5.6.1
这里要特别说明一下,RealSense的开发对软硬件都有要求,官方SDK文档中是这样描述的:

这里写图片描述

这里的硬件特别是CPU的描述太过笼统,实际上不用看型号,而需要看CPU以及GPU是否支持OpenCL 1.2以上版本,注意是CPU和GPU都必须满足该条件,我在官网论坛上看到有人的GPU支持OpenCL 1.2,CPU支持OpenCL 1.1,结果导致初始化失败。但是如何检测呢,大家可以用Geeks3D GPU Caps Viewer这款软件,如下图,第一条红线处会显示支持OpenCL的硬件(包括CPU和GPU),选中可在下方显示支持的OpenCL版本。

这里写图片描述

另外,需要安装:
1. 对应的DCM(Depth Camera Manager),也是驱动;
2. 对应的SDK,至少需要core,其他可按需下载face,hand,cursor,scan3d,seg3d等;
提醒一下:以上文件需要翻墙上Intel官网,并注册账号才能下载,下载后都是exe文件,默认安装即可。


开发正文

SDK安装完毕后,可使用生成到桌面的“Intel® RealSense™ SDKTools”中Tools: “Camera Explorer”检测摄像头是否可正常使用。

这里写图片描述

这个文件夹中包含了一些官方的样例(Samples文件夹下),但遗憾的是我选择的样例“RawStreams.unity”是无法正常使用的,用Unity直接打开后没有报错,两个分别用于显示彩色图像和深度图像的Plane只是由白色变成了灰色,仅此而已,使用断点调试可以发现SenesManger实例.Init()返回的Status值为Status_Item_Unavaliable,因为这个原因,我先后更换了Unity版本和RealSense SDK版本,耗费了大量时间(没办法,菜鸟程序员会瞎猜),后面说初始化失败的真实原因。
这里顺便说一下,当前Intel RealSense SDK的版本是R3,这个版本不再支持R200,参考这里,所以需要下载R2版本,参考这里,,请注意。
好了,下面正式贴工程代码。


一、新建Unity工程,导入SDK R2提供的UnityToolkit.unitypackage开发包,默认存放目录是:C:Program Files (x86)IntelRSSDKframeworkUnity。
二、创建两个RawImage分别用于显示彩色图像和深度图像,创建两个Material分别赋予两个RawImage,Shader可以用Unlit/Texture。

这里写图片描述

三、创建空物体,命名为RawStreamController,并创建同名C#脚本,赋给该空物体。
四、编写代码。
1. 定义变量

[Header("Color Settings")]
    public int colorWidth = 640;
    public int colorHeight = 480;
    public Material RGBMaterial;

    [Header("Depth Settings")]
    public int depthWidth = 628;
    public int depthHeight = 468;
    public Material DepthMaterial;
    //实例
    private PXCMSenseManager psm = null;
    //深度图像
    private Texture2D depthImageTexture2D = null;
    //彩色图像
    private Texture2D colorImageTexture2D = null;

特别说明:注意depthWidth和depthHeight两个值,官方文档和网上教程大多都是640和480,但是这是错误的,这两个数字就是导致初始化失败的原因,这里要特别感谢理想国的博客,是他指出了问题所在,简单说就是Intel实感摄像头的颜色和深度分辨率是有限制的,官方SDK文档给出的条件如下:

这里写图片描述

放大一点:

这里写图片描述

内容在开发手册“Developer Guide (CHM)”中的Advanced Topics/Working With Multiple Modalities目录下。
2. 初始化

void Start () {
        if (psm != null) return;

        //创建实例
        psm = PXCMSenseManager.CreateInstance();

        if(psm == null)
        {
            Debug.LogError("PXCMSenseManager Initialization Failed!");
            return;
        }
        //激活流事件
        psm.EnableStream(PXCMCapture.StreamType.STREAM_TYPE_COLOR, colorWidth, colorHeight);
        psm.EnableStream(PXCMCapture.StreamType.STREAM_TYPE_DEPTH, depthWidth, depthHeight);
        //初始化
        pxcmStatus status = psm.Init();

        if(status < pxcmStatus.PXCM_STATUS_NO_ERROR)
        {
            Debug.LogError("Stream Pipeline Init Failed!");
            return;
        }
    }
  1. 每帧获取数据
void Update () {
        if (psm == null)
            return;
        //抓取帧数据
        if(psm.AcquireFrame(false,0) < pxcmStatus.PXCM_STATUS_NO_ERROR)
        {
            return;
        }

        //创建Sample
        PXCMCapture.Sample sample = psm.QuerySample();
        if(sample != null)
        {
            OnSampleRetrieve(sample);
        }

        psm.ReleaseFrame();
    }

4.处理图像

private void OnSampleRetrieve(PXCMCapture.Sample sample)
    {
        //接收颜色数据
        PXCMImage.ImageInfo colorImgInfo = new PXCMImage.ImageInfo();
        colorImgInfo.width = colorWidth;
        colorImgInfo.height = colorHeight;
        colorImgInfo.format = PXCMImage.PixelFormat.PIXEL_FORMAT_RGB24;
        PXCMImage colorImg = psm.session.CreateImage(colorImgInfo);

        colorImg = sample.color;
        //接收深度数据
        PXCMImage.ImageInfo depthImgInfo = new PXCMImage.ImageInfo();
        depthImgInfo.width = depthWidth;
        depthImgInfo.height = depthHeight;
        depthImgInfo.format = PXCMImage.PixelFormat.PIXEL_FORMAT_RGB24;
        PXCMImage depthImg = psm.session.CreateImage(depthImgInfo);

        depthImg = sample.depth;
        //
        if (colorImg != null)
        {
            if (colorImageTexture2D == null)
            {
                colorImageTexture2D = new Texture2D(colorWidth, colorHeight, TextureFormat.RGB24, false);
                RGBMaterial.mainTexture = colorImageTexture2D;
                RGBMaterial.mainTextureScale = new Vector2(-1, -1);
            }
        }
        if(depthImg != null)
        {
            if(depthImageTexture2D == null)
            {
                depthImageTexture2D = new Texture2D(depthWidth, depthHeight, TextureFormat.RGB24, false);
                DepthMaterial.mainTexture = depthImageTexture2D;
                DepthMaterial.mainTextureScale = new Vector2(-1, -1);
            }
        }
        //
        PXCMImage.ImageData colorImageData;
        colorImg.AcquireAccess(PXCMImage.Access.ACCESS_READ, out colorImageData);
        colorImageData.ToTexture2D(0, colorImageTexture2D);
        colorImg.ReleaseAccess(colorImageData);
        colorImageTexture2D.Apply();

        PXCMImage.ImageData depthImageData;
        depthImg.AcquireAccess(PXCMImage.Access.ACCESS_READ, out depthImageData);
        depthImageData.ToTexture2D(0, depthImageTexture2D);
        depthImg.ReleaseAccess(depthImageData);
        depthImageTexture2D.Apply();
    }

获取颜色图像和深度图像的过程是一样的,大家可以省略着看。
5.结束

private void OnDisable()
    {
        if (psm != null)
            psm.Dispose();
    }

最后贴上运行成功的结果:

这里写图片描述

声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。