总算在Linux下把OpenNI和OPenCV配置好了,网上对Linux下OpenNI的配置方法讲的很少,而寻找使用OpenNI进行开发的方法更是像大海捞针……连手册里都只字不提,翻了好的资料才算搞定。闲话少说,总结在这和大家一起分享。
一、OPenNI篇
1.软件下载:
选择“OpenNI Binaries”->“Unstable”->“...for Ubuntu...”,点击“Download”。
下载完成后解压,cd进入解压后的路径:$ ./install.sh(不记得要不要加sudo了,试一试吧)
(2)SensorKinect:
命令:$git clone https://github.com/avin2/SensorKinect.git
如果没有安装git,则sudo apt-get install之~
过程比较慢,结束后会在当前路径出现一个文件夹SensorKinect,cd进SensorKinect/Platform/Linux/CreateRedist,之后$ ./RedistMaker,这时在上层目录Linux下出现Redist文件夹。此时网上说进该目录$ ./install.sh,但实际上还要进一层目录才有instal.sh文件。但是貌似执行这个需要root权限,我不知道怎么弄,$sudo su后也不行,最后发现还是Redist文件夹里面有一个Final文件夹,里面有一个压缩包Sensor-Bin-Linux-x86-v5.0.5.1.tar.bz2,我索性把它拷出来,解压缩后进去 (…/SensorKinect/Platform/Linux/CreateRedist/Sensor-Bin-Linux-x86-v5.0.5.1/),在里面$./install.sh,竟然就可以了。顺便说一下,可能在这些过程中输入$ ./install.sh 会提示没有命令之类的,可以在install.sh文件上右击->属性->权限,选中“允许以程序执行文件”,就可以了。
这时可以到在OpenNI-Bin-XXXX/Samples/Bin/x86-Release目录中测试:$ ./NiViewer,有可能提示没有什么库之类的,试着装一下:$sudo apt-get install libusb-1.0-0-dev freeglut3-dev,之后应该就可以运行了,就可以看到期待已久的画面喽。如果这时候提示说Failed to set USB interface!或者Open failed: The network connection has been closed!,在命令行里运行:
$sudo rmmod gspca_kinect
这是因为Ubuntu可能自带了kinect驱动gspca_kinect,二者有冲突。貌似每次重启电脑后都需要执行一下这句才行。如果不想这么麻烦,可以把这个驱动加入系统黑名单:
$sudo gedit /etc/modprobe.d/blacklist.conf
在打开的文件底部加入一行:
blacklist gspca_kinect
这部分主要参考了https://github.com/avin2/SensorKinect里面讲的可能和实际不太一样,尝试着来吧。
选择“OpenNI Compliant Middleware Binaries”->“Unstable”->“...Ubuntu...”,下载就好了。
下载完成后解压,进入目录$ ./install.sh即可。
2.开发环境配置
我选用的是eclipse-cdt进行开发,网上仅有的可怜的一点资料讲的是用codeblocks进行开发,其实都是差不多的。这里以eclipse为例介绍一下吧。
新建一个空的或helloworld工程,如kinectOpenNI,在左侧的project exploer中右击kinectOpenNI,点properties,在对话框中选择C/C++ Build->settings->GCC C++ Compiler(如果用C写就选GCC C Compiler)->Directories,在右侧Include paths(-l)里点右边绿色加号,添加两个路径/usr/include/ni和/usr/include/nite,然后再选择GCC C++ Linker->Libraries,在Libraries (-l)中添加OpenNI,glut,XnVNite,注意XnVNite可能有版本号,要到你的/usr/lib目录下看一看,有个文件叫libXnVNite_XXXX.so之类的,我的是libXnVNite_1_5_0.so,所以我填的是XnVNite_1_5_0,反正就是随机应变吧,填不对的话它会报错说找不到库。由于这几个库都是在系统/usr/lib/目录下的,因此不用添加Library search path (-L)。
到此为止你的工程应该可以编译了。试试这段样例:(注意该一下里面xml文件的路径。样例是直接从安装包里找到的。当然,记得连上你的Kinect)
/***************************************************************************** *
* OpenNI 1.x Alpha *
* Copyright (C) 2011 PrimeSense Ltd. *
* *
* This file is part of OpenNI. *
* *
* OpenNI is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* OpenNI is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with OpenNI. If not, see <>. *
* *
****************************************************************************/
//---------------------------------------------------------------------------
// Includes
//---------------------------------------------------------------------------
#include <XnOS.h>
#if (XN_PLATFORM == XN_PLATFORM_MACOSX)
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <math.h>
#include <XnCppWrapper.h>
using namespace xn;
//---------------------------------------------------------------------------
// Defines
//---------------------------------------------------------------------------
#define SAMPLE_XML_PATH "/home/iotuyrfviloh/Softwares/OpenNI-Bin-Dev-Linux-x86-v1.4.0.2/Samples/Config/SamplesConfig.xml"
#define GL_WIN_SIZE_X 1280
#define GL_WIN_SIZE_Y 1024
#define DISPLAY_MODE_OVERLAY 1
#define DISPLAY_MODE_DEPTH 2
#define DISPLAY_MODE_IMAGE 3
#define DEFAULT_DISPLAY_MODE DISPLAY_MODE_DEPTH
#define MAX_DEPTH 10000
//---------------------------------------------------------------------------
// Globals
//---------------------------------------------------------------------------
float g_pDepthHist[MAX_DEPTH];
XnRGB24Pixel* g_pTexMap = NULL;
unsigned int g_nTexMapX = 0;
unsigned int g_nTexMapY = 0;
unsigned int g_nViewState = DEFAULT_DISPLAY_MODE;
Context g_context;
ScriptNode g_scriptNode;
DepthGenerator g_depth;
ImageGenerator g_image;
DepthMetaData g_depthMD;
ImageMetaData g_imageMD;
//---------------------------------------------------------------------------
// Code
//---------------------------------------------------------------------------
void glutIdle (void)
{
// Display the frame
glutPostRedisplay();
}
void glutDisplay (void)
{
XnStatus rc = XN_STATUS_OK;
// Read a new frame
rc = g_context.WaitAnyUpdateAll();
if (rc != XN_STATUS_OK)
{
printf("Read failed: %s\n", xnGetStatusString(rc));
return;
}
g_depth.GetMetaData(g_depthMD);
g_image.GetMetaData(g_imageMD);
const XnDepthPixel* pDepth = g_depthMD.Data();
const XnUInt8* pImage = g_imageMD.Data();
unsigned int nImageScale = GL_WIN_SIZE_X / g_depthMD.FullXRes();
// Copied from SimpleViewer
// Clear the OpenGL buffers
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Setup the OpenGL viewpoint
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, GL_WIN_SIZE_X, GL_WIN_SIZE_Y, 0, -1.0, 1.0);
// Calculate the accumulative histogram (the yellow display...)
xnOSMemSet(g_pDepthHist, 0, MAX_DEPTH*sizeof(float));
unsigned int nNumberOfPoints = 0;
for (XnUInt y = 0; y < g_depthMD.YRes(); ++y)
{
for (XnUInt x = 0; x < g_depthMD.XRes(); ++x, ++pDepth)
{
if (*pDepth != 0)
{
g_pDepthHist[*pDepth]++;
nNumberOfPoints++;
}
}
}
for (int nIndex=1; nIndex<MAX_DEPTH; nIndex++)
{
g_pDepthHist[nIndex] += g_pDepthHist[nIndex-1];
}
if (nNumberOfPoints)
{
for (int nIndex=1; nIndex<MAX_DEPTH; nIndex++)
{
g_pDepthHist[nIndex] = (unsigned int)(256 * (1.0f - (g_pDepthHist[nIndex] / nNumberOfPoints)));
}
}
xnOSMemSet(g_pTexMap, 0, g_nTexMapX*g_nTexMapY*sizeof(XnRGB24Pixel));
// check if we need to draw image frame to texture
if (g_nViewState == DISPLAY_MODE_OVERLAY ||
g_nViewState == DISPLAY_MODE_IMAGE)
{
const XnRGB24Pixel* pImageRow = g_imageMD.RGB24Data();
XnRGB24Pixel* pTexRow = g_pTexMap + g_imageMD.YOffset() * g_nTexMapX;
for (XnUInt y = 0; y < g_imageMD.YRes(); ++y)
{
const XnRGB24Pixel* pImage = pImageRow;
XnRGB24Pixel* pTex = pTexRow + g_imageMD.XOffset();
for (XnUInt x = 0; x < g_imageMD.XRes(); ++x, ++pImage, ++pTex)
{
*pTex = *pImage;
}
pImageRow += g_imageMD.XRes();
pTexRow += g_nTexMapX;
}
}
// check if we need to draw depth frame to texture
if (g_nViewState == DISPLAY_MODE_OVERLAY ||
g_nViewState == DISPLAY_MODE_DEPTH)
{
const XnDepthPixel* pDepthRow = g_depthMD.Data();
XnRGB24Pixel* pTexRow = g_pTexMap + g_depthMD.YOffset() * g_nTexMapX;
for (XnUInt y = 0; y < g_depthMD.YRes(); ++y)
{
const XnDepthPixel* pDepth = pDepthRow;
XnRGB24Pixel* pTex = pTexRow + g_depthMD.XOffset();
for (XnUInt x = 0; x < g_depthMD.XRes(); ++x, ++pDepth, ++pTex)
{
if (*pDepth != 0)
{
int nHistValue = g_pDepthHist[*pDepth];
pTex->nRed = nHistValue;
pTex->nGreen = nHistValue;
pTex->nBlue = 0;
}
}
pDepthRow += g_depthMD.XRes();
pTexRow += g_nTexMapX;
}
}
// Create the OpenGL texture map
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, g_nTexMapX, g_nTexMapY, 0, GL_RGB, GL_UNSIGNED_BYTE, g_pTexMap);
// Display the OpenGL texture map
glColor4f(1,1,1,1);
glBegin(GL_QUADS);
int nXRes = g_depthMD.FullXRes();
int nYRes = g_depthMD.FullYRes();
// upper left
glTexCoord2f(0, 0);
glVertex2f(0, 0);
// upper right
glTexCoord2f((float)nXRes/(float)g_nTexMapX, 0);
glVertex2f(GL_WIN_SIZE_X, 0);
// bottom right
glTexCoord2f((float)nXRes/(float)g_nTexMapX, (float)nYRes/(float)g_nTexMapY);
glVertex2f(GL_WIN_SIZE_X, GL_WIN_SIZE_Y);
// bottom left
glTexCoord2f(0, (float)nYRes/(float)g_nTexMapY);
glVertex2f(0, GL_WIN_SIZE_Y);
glEnd();
// Swap the OpenGL display buffers
glutSwapBuffers();
}
void glutKeyboard (unsigned char key, int x, int y)
{
switch (key)
{
case 27:
exit (1);
case '1':
g_nViewState = DISPLAY_MODE_OVERLAY;
g_depth.GetAlternativeViewPointCap().SetViewPoint(g_image);
break;
case '2':
g_nViewState = DISPLAY_MODE_DEPTH;
g_depth.GetAlternativeViewPointCap().ResetViewPoint();
break;
case '3':
g_nViewState = DISPLAY_MODE_IMAGE;
g_depth.GetAlternativeViewPointCap().ResetViewPoint();
break;
case 'm':
g_context.SetGlobalMirror(!g_context.GetGlobalMirror());
break;
}
}
int main(int argc, char* argv[])
{
XnStatus rc;
EnumerationErrors errors;
rc = g_context.InitFromXmlFile(SAMPLE_XML_PATH, g_scriptNode, &errors);
if (rc == XN_STATUS_NO_NODE_PRESENT)
{
XnChar strError[1024];
errors.ToString(strError, 1024);
printf("%s\n", strError);
return (rc);
}
else if (rc != XN_STATUS_OK)
{
printf("Open failed: %s\n", xnGetStatusString(rc));
return (rc);
}
rc = g_context.FindExistingNode(XN_NODE_TYPE_DEPTH, g_depth);
if (rc != XN_STATUS_OK)
{
printf("No depth node exists! Check your XML.");
return 1;
}
rc = g_context.FindExistingNode(XN_NODE_TYPE_IMAGE, g_image);
if (rc != XN_STATUS_OK)
{
printf("No image node exists! Check your XML.");
return 1;
}
g_depth.GetMetaData(g_depthMD);
g_image.GetMetaData(g_imageMD);
// Hybrid mode isn't supported in this sample
if (g_imageMD.FullXRes() != g_depthMD.FullXRes() || g_imageMD.FullYRes() != g_depthMD.FullYRes())
{
printf ("The device depth and image resolution must be equal!\n");
return 1;
}
// RGB is the only image format supported.
if (g_imageMD.PixelFormat() != XN_PIXEL_FORMAT_RGB24)
{
printf("The device image format must be RGB24\n");
return 1;
}
// Texture map init
g_nTexMapX = (((unsigned short)(g_depthMD.FullXRes()-1) / 512) + 1) * 512;
g_nTexMapY = (((unsigned short)(g_depthMD.FullYRes()-1) / 512) + 1) * 512;
g_pTexMap = (XnRGB24Pixel*)malloc(g_nTexMapX * g_nTexMapY * sizeof(XnRGB24Pixel));
// OpenGL init
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(GL_WIN_SIZE_X, GL_WIN_SIZE_Y);
glutCreateWindow ("OpenNI Simple Viewer");
glutFullScreen();
glutSetCursor(GLUT_CURSOR_NONE);
glutKeyboardFunc(glutKeyboard);
glutDisplayFunc(glutDisplay);
glutIdleFunc(glutIdle);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
// Per frame code is in glutDisplay
glutMainLoop();
return 0;
}