基于OpenNI2(win64) 的Structure Sensor应用开发完整教程
来源:互联网 发布:中准会计师事务所 知乎 编辑:程序博客网 时间:2024/06/14 06:44
工具准备
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工程
- 基于OpenNI2(win64) 的Structure Sensor应用开发完整教程
- 便携式3D扫描仪 structure sensor openni2的快速启动向导
- OpenNI2的安装教程
- Kinect开发教程七:OpenNI2自带范例程序的编译执行
- Kinect开发教程七:OpenNI2自带范例程序的编译执行
- 浅析OpenNI2---Driver开发(1)
- 浅析OpenNI2---Driver开发(2)
- Sensor传感器源码的阅读与应用开发简单实例
- Sensor传感器源码的阅读与应用开发…
- Sensor传感器源码的阅读与应用开发…
- eclipse-java-helios-SR2-win32和win64 汉化包下载地址和汉化方法(完整图文教程)
- Android开发教程之感应检测Sensor
- 基于树的建模-完整教程(R & Python)
- TI-CC2640R2-Sensor Controller 开发应用
- Kinect开发教程六:OpenNI2简介、安装与VS开发环境配置
- Kinect开发教程六:OpenNI2简介、安装与VS开发环境配置
- Win64 Driver开发问题记录(一)
- Win64 Driver开发问题记录(二)
- java__线程
- poj 2686 状压dp
- 微信公众平台开发教程第22篇-如何保证access_token长期有效
- grub2的配置文件grub.cfg详解
- 消息队列
- 基于OpenNI2(win64) 的Structure Sensor应用开发完整教程
- memcpy与memmove的区别及源码
- redhat 6.4安装opencv3.0.0
- 使用 nohup 让进程在后台运行
- c#跨线程操作问题
- 总结八大排序算法的基本思想与代码实现
- JavaWeb这三周-FrameSet框架实现新闻后台管理系统
- Spring学习(十五)使用quartz子框架实现任务调度
- 黑马程序员-----------C语言基础-----------结构体·枚举