基于OpenNI2(win64) 的Structure Sensor应用开发完整教程

工具准备

1.从http://www.structure.io/openni 下载OpenNI-Windows-x64-2.2.0.33.zip
2.打开zip,运行其中的msi文件。安装完毕注销windows并重新登入(安装完毕后,将有两个新的环境变量OPENNI2_INCLUDE64,OPENNI2_LIB64被添加到系统环境变量中)
3.准备好visual studio 2010 或更高版本

创建第一个工程

新建win32控制台应用程序

这里写图片描述

配置工程依赖项

配置库的输入目录
配置输入的库
配置头文件包含

编写代码

以下代码是对OpenNI2提供的范例进行的归纳,任何与OpenNI2及深度传感器无关的代码都被略去。

启动OpenNI2和设备

以下是常规的读取深度帧的上下文初始化过程,其梗概是:
启动OpenNI2—>打开一个传感器设备—>通过设备创建一个视频流(这个流可以是深度图像流,颜色图像流或其他设备支持的流)

    openni::Status rc = openni::STATUS_OK;
    rc = openni::OpenNI::initialize();

    printf("After initialization:\n%s\n", openni::OpenNI::getExtendedError());

    openni::Device device;
    rc = device.open(openni::ANY_DEVICE);
    if (rc != openni::STATUS_OK)
    {
        printf("DepthSensor Viewer: Device open failed:\n%s\n", openni::OpenNI::getExtendedError());
        openni::OpenNI::shutdown();
        return 1;
    }

    openni::VideoStream depth;
    rc = depth.create(device, openni::SENSOR_DEPTH);
    auto videomode = new openni::VideoMode();
    videomode->setFps(30);
    videomode->setPixelFormat(openni::PIXEL_FORMAT_DEPTH_100_UM);
    videomode->setResolution(160, 120);
    depth.setVideoMode(*videomode);
    if (rc == openni::STATUS_OK)
    {
        rc = depth.start();
        if (rc != openni::STATUS_OK)
        {
            printf("DepthSensor Viewer: Couldn't start depth stream:\n%s\n", openni::OpenNI::getExtendedError());
            depth.destroy();
        }
    }
    else
    {
        printf("DepthSensor Viewer: Couldn't find depth stream:\n%s\n", openni::OpenNI::getExtendedError());
    }
    // m_streams 将在后面的代码片段中被用到,我们需要一个指针的数组作为参数
    m_streams = new VideoStream*[1];
    m_streams[0] = depth;

在自定义的上下文中读取深度帧并渲染

你可以将下面的代码放置在渲染线程的循环中,比如通过glut窗口系统的glutDisplayFunc()注册的回调函数中

    int changedIndex;
    openni::Status rc = openni::OpenNI::waitForAnyStream(m_streams, 2, &changedIndex);
    openni::VideoFrameRef       depthFrame;
    m_streams[changedIndex]->readFrame(&depthFrame);
    /// 我们已经拿到了数据,现在可以用你想要的方式进行绘制了, 典型的绘制如下:将数据转为RGB纹理图片
    const openni::DepthPixel* pDepthRow = (const openni::DepthPixel*)depthFrame.getData();
    openni::RGB888Pixel* pTexRow = m_pTexMap + m_depthFrame.getCropOriginY() * m_nTexMapX;

    int rowSize = depthFrame.getStrideInBytes() / sizeof(openni::DepthPixel);

    for (int y = 0; y < depthFrame.getHeight(); ++y)
    {
        const openni::DepthPixel* pDepth = pDepthRow;
        openni::RGB888Pixel* pTex = pTexRow + depthFrame.getCropOriginX();

        for (int x = 0; x < depthFrame.getWidth(); ++x, ++pDepth, ++pTex)
        {
            if (*pDepth != 0)
            {
                char value = 255 - ((float)(*pDepth) / (float)256);       ///DepthPixel是两个字节的,需要将其压缩为1个字节;
       ///这种转换效果也许不是最好的,关于这可以查看OpenNI2的例子SimpleViewer
                pTex->r = value;
                pTex->g = value;
                pTex->b = 0;
                }
            }

            pDepthRow += rowSize;
            pTexRow += m_nTexMapX;
        }
    }     

当然,OpenNI2 也提供了将深度值转换为世界坐标系下的3维坐标的API:

void depthPixelToWorld3d(const openni::VideoStream& depthStream, int depthX, int depthY,openni::DepthPixel depthZ, float world3d[3])
{
    openni::CoordinateConverter::convertDepthToWorld(depthStream, depthX, depthY,depthZ, &world3d[0],
        &world3d[1], &world3d[2]);
}
    const openni::DepthPixel* pDepthRow = (const openni::DepthPixel*)depthFrame.getData();
    int depthYStart = depthFrame.getCropOriginY();
    int depthXStart = depthFrame.getCropOriginX();
    int rowSize = depthFrame.getStrideInBytes() / sizeof(openni::DepthPixel);   
    auto points= new float[depthFrame.getWidth()* depthFrame.getHeight()][3];
    int pointCounts = 0;
    for (int y = 0; y < depthFrame.getHeight(); ++y)
    {
        const openni::DepthPixel* pDepth = pDepthRow;

        for (int x = 0; x < depthFrame.getWidth(); ++x, ++pDepth)
        {
            if (*pDepth != 0)
            {
                depthPixelToWorld3d(depthStream, depthXStart + x,
                    depthYStart + y, *pDepth, points[pointCounts]);
                ++pointCounts;
            }
        }
        pDepthRow += rowSize;
    }

运行程序

用USB连接StructureSensor,并将OpenNI2/Redist目录下的所有文件和文件夹拷贝到应用程序的同一目录下,运行程序。如果程序不能找到设备,请抽出USB数据线并重新连接。

可能存在的问题

openni::CoordinateConverter::convertDepthToWorld()所输出的世界坐标的XYZ分量的值并不是以毫米为单位

这是OpenNI2社区最近才修复的bug:
https://github.com/occipital/OpenNI2/commit/1fce8edffab43c4a4cf201cff86f415b07a2d37f
要想解决这个问题,只能自己编译OpenNI2。从https://github.com/occipital/OpenNI2下载最新的zip源码。无须下载该页面所指出的其他内容,直接运行源码包中的Visual Studio sln文件,生成其中的OpenNI工程,将生成的OpenNI2.dll拷贝到应用程序所在目录,替换旧的OpenNI2.dll

自己编译完整的OpenNI2安装包

如果需要生成完整的OpenNI2安装包,请使用Visual Studio 2010,并安装
WIX 3.5 http://wix.codeplex.com/releases/view/60102 。运行OpenNI.sln 并生成解决方案下的Install工程

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值