Home People Research Blog Courses Links Search Download
NCHC

Blog

Blog 最新文章

  1. Visual Studio 2019 16.9 支援使用 OpenMP LLVM
    2021/03/03 13:52
  2. Valve 推出完全支援 OpenXR 的 SteamVR 1.16.8
    2021/02/25 09:43
  3. 讓 Oculus Quest 2 變 PC VR:Oculus Link
    2021/02/22 11:25

Blog 最新回應

  1. 加入斜體文字...
    2021/02/07 21:06
  2. 加入斜體文字...
    2021/02/07 21:06
  3. 加入斜體文字...
    2021/02/07 21:06

Keyword 關鍵字

Boost 3D立體 Vulkan C++14 OpenVR Oculus Rift S Valve Index Docker 開放資料 Windows MR VR Pandas Kinect MR C++14 C++20 PHP VR Oculus OpenCL Python GitLab Oculus Quest 2 NiTE2 HTC Vive Pandas HTC Vive Focus OpenNI 開放資料 Qt svn Python iFlyover C++11 OpenCV OpenGL CubeX C++ Java OpenNI2 HTC Vive Pro ASUS Xtion Docker 3d print WebGL 資料視覺化 CUDA javascript HoloLens 2 xml C++17 OpenMP git OpenXR 資訊地圖

類別:技術相關 » 技術研究
文章發表|我要回應|RSS訂閱

Kinect 的軟體開發方案:OpenNI 簡介

image之前已經介紹過了微軟給 XBox 360 用的體感輸入裝置 Kinect 了;後來也陸續介紹了怎麼樣在 Windows 上,透過 OpenNI 來使用 Kinect 作一些應用(文章一、文章二)。

而接下來則是準備往技術面,來介紹一下,要怎麼樣用 C 來使用 OpenNI 了∼不過這一篇,則是在進入到程式的部分前,先大概介紹一下 OpenNI 這個 Framework 的基本架構了。

OpenNI 簡介

首先,什麼是 OpenNI?他是「Open Natural Interaction」的縮寫,大致上可以翻譯為「開放式自然操作」;而所謂的 NI 又包含哪些東西呢?OpenNI 對自然操作(Natural Interaction,以下簡稱 NI)的定義包含了「語音」、「手勢」、「身體動作」等等,基本上就是比較直覺、操作者身上不需要其他特殊裝置的操作方式了。

OpenNI 本身則是定義了撰寫自然操作程式所需要的 API,提供一個多語言(主要是 C/C )、跨平台的 framework;藉此提供了一個標準的介面,讓程式開發者要使用視覺、聲音相關感應器,以及對於這些資料、分析的中介軟體(middleware)時,可以更為方便。

下方則是 OpenNI 的基本架構圖:

image

上面的架構圖基本上分為三層,最上層是應用程式(Application),也就是我們這些程式開發者自己要撰寫的部分;最下方的一層則是硬體的部分,目前 OpenNI 支援的硬體,包含了:3D Sensor、RGB Camera、IR Camera、Audio Device 這四類。不過以目前來說,會用 OpenNI 的人,主要應該就是用 Kinect 了∼而如果能有對應的驅動程式的話,其他類似的裝置,應該也是有機會可以讓 OpenNI 來存取的。

而中間這層就是 OpenNI 的部分,他除了負責和硬體的溝通外,也在自身內部預留了加上中介軟體(middleware)的空間,可以用來做手勢辨識、或是追蹤之類的處理。OpenNI 目前在 middleware 的部分,定義了下面四種元件:

  • 全身分析(Full body analysis)

    由感應器取得的資料,產生身體的相關資訊,例如關節、相對位置與角度、質心等等。

  • 手部分析(Hand point analysis)

    追蹤手的位置。

  • 手勢偵測(Gesture detection)

    辨識預先定義好的手勢,例如揮手。

  • 場景分析(Scene Analyzer)

    分析場景內的資訊,例如:分離前景和背景、地板的座標軸、辨識場景內的不同物體。

目前 PrimeSense 也已經提供了一套 NITE 當作最主要的 middleware、提供上面所列的功能;而如果有更進階的需求的話,應該也可以自己寫一套相容於 OpenNI 的 middleware 來使用。當然,也希望以後會有其他軟體廠商投入這塊來開發了。

節點(Node)

在 OpenNI 裡,他定義了所謂的「Production Node」來代表內部的基本單元,包括了硬體部分的感應器,以及 OpenNI 所提供的功能;這些 production node 分為下面三大類/層:

  1. 感應器相關(Sensor Related)Production Nodes
    • 裝置(Device) :代表實體裝置的節點,主要是用來做這些設備的設定。
    • 深度產生器(Depth Generator):產生深度資訊圖(depth-map)的節點。
    • 影像產生器(Image Generator):產生彩色影像圖(colored image-maps)的節點。
    • 紅外線影像產生器(IR Generator):產生紅外線影像圖(IR image-maps)的節點。
    • 聲音產生器(Audio Generator):產生聲音串流(audio stream)的節點。
  2. 中介軟體相關(Middleware Related)Production Nodes
    • 手勢通知產生器(Gestures Alert Generator):當辨識到特定的手勢時,呼叫應用程式的 callback。
    • 場景分析器(Scene Analyzer):分析場景,包括分離前景與背景、識別場景內的不同物體、偵測地板。他主要的輸出會是標記過的深度資訊圖(labeled depth map)。
    • 手部位置產生器(Hand Point Generator):支援手部偵測與追蹤,當偵測到手、或追蹤手的位置時,會產生一個通知訊息。
    • 使用者產生器(User Generator):產生一個 3D 場景中完整、或局部的身體資訊。
  3. 錄製/撥放
    • 錄製器(Recorder):用來記錄資料用的。
    • 撥放器(Player):讀取記錄下來的資料,並撥放出來。
    • 編解碼器(Codec):用來壓縮、解壓縮紀錄資料。

上面這些 Production Node 基本上都是會由不同的模組各自實作的。像是以感應器相關的部分,就是會由 OpenNI 相容的裝置提供,以目前來說,主要就是 Kinect 的驅動程式會提供這深度、影像產生的功能。而中介軟體相關的部分,則是由不同的 middleware 各自提供;不過目前的來源應該也只有 NITE 就是了。

在層級上,感應器相關的 production node 算是最底層的,由於去直接存取設備的資料,所以應用程式可以直接使用這類的 production node。而中介軟體相關的 production node 由於是靠感應器的資料來做處理的,所以他們的層級則比感應器的高一層、必須要在有感應器相關的 production node 的情況下才可以使用。

而在有了上面的這些 Production Node 後,就可以透過組合這些節點來建立所謂的「Production Chain」,並以此進行資料的處理流程。比如說要產生使用者的資料的話,就是會透過「使用者產生器」(User Generator)去存取更低層的「深度產生器」(Depth Generator);而這樣的一個節點序列,就是所謂的「Production Chain」。

能力(Capability)

OpenNI 的「Capability」機制是用來增強中介軟體和硬體裝置的彈性的;這些不同的能力都是非必要性的,各家廠商所提供的不同的中介軟體和裝置,可以自己決定要提供那些能力。而 OpenNI 則是負責定義好一些可以使用的 capability,讓程式開發者可以快速地找到符合自己需求的中介軟體或裝置。

而目前版本的 OpenNI 所支援的 capability 則如下:

  • 替換視角(Alternative View)

    讓各類型的 map generator(深度、影像、紅外線) 可以轉換到別的視角,就好像攝影機在別的位置一樣。這個功能可以快速地替不同的感應器產生的內容作對位。

  • 裁切(Cropping)

    讓各類型的 map generator(深度、影像、紅外線) 輸出結果可以被裁切、降低解析度;例如:VGA 可以裁切成 QVGA。這對效能的增進很有用。

  • 畫面同步(Frame Sync)

    讓兩個感應器產生結果同步化,藉此可以同步取得不同感應器的資料。

  • 鏡像(Mirror)

    把產生的結果鏡像(左右顛倒)。

  • 姿勢偵測(Pose Detection)

    讓「使用者產生器(User Generator)」可以偵測出使用者特定的姿勢。

  • 骨架(Skeleton)

    讓「使用者產生器(User Generator)」可以產生使用者的骨架資料。包含骨架關節的位置、並包含追蹤骨架位置和使用者校正的能力。

  • 使用者位置(User Position)

    讓「深度產生器(Depth Generator)」可以針對指定的場景區域、最佳化輸出的深度影像。

  • 錯誤狀態(Error State)

    讓節點可以回報他本身的錯誤狀態。

  • Lock Aware

    讓節點可以在 context 範圍外被鎖定。詳見《Sharing Devices between Applications and Locking Nodes》。

基本上,這些 capability 許多都是只針對特定的 Production Node 才會有的(例如 skeleton 就只有 user 這類的 node 可能有);而至於那些 Production Node 有哪些 capability 呢,就是要看更細一部的資料才會知道了∼

而這篇文章,也就先寫到這裡了。當然,OpenNI 還有滿多東西,Heresy 在這就暫時先跳過了∼下一篇開始,應該就是會使用 OpenNI,來寫一些簡單的範例了∼

參考資料:《OpenNI User Guide》

張貼者:heresy於2011/01/17 11:39 上午有40則回應,瀏覽次數:24,160次
Dean 於 2011/01/29 16:24 下午 回應:
你好,你的文章對我大有裨益,不過可不可以介紹一下kinect語音識別方面的應用。謝謝!
作者作者heresy 於 2011/01/29 16:52 下午 回應:
抱歉,目前暫時應該還不會研究到語音的部分。
led 於 2011/02/24 03:33 上午 回應:
你好~想問一下大大~~因為我的英文不大好 = = 但我想好好看完《OpenNI User Guide》裡面提供的資訊~~不知道有沒有中文的可以看 = =
作者作者heresy 於 2011/02/24 22:23 下午 回應:
to led目前應該沒有中文版的文件喔。
ilpisces 於 2011/03/01 20:30 下午 回應:
很高興学习了!另,有没有针对MAC的openNI使用方法的介绍?
作者作者heresy 於 2011/03/01 21:04 下午 回應:
to ilpisces 抱歉,Heresy 沒有 Mac
仔仔 於 2011/07/11 15:25 下午 回應:
好文章啊,慢慢??了
Chocolate 於 2011/09/01 13:49 下午 回應:
heresy您好,我是新手,现在在做一个KINECT的开发。 我想问一下您:使用OPENNI所获得的KINECT侦测到的数据如何用呢? 比如说,我想使用KINECT作为遥控器来控制灯的亮灭。应该如何使用OPENNI提取到的数据呢?能不能大概的说说、谢谢
作者作者heresy 於 2011/09/01 13:53 下午 回應:
@Chocolate 基本上這主要取決於你要怎麼定義控制的方法。最簡單的方法,就是直接使用 NITE 所定義的手勢、並在偵測到指定的手勢的時候,去做你要做的動作。不然,就是要自己去定義其他的判斷條件,來做是否要執行的檢查了
。
Chocolate 於 2011/09/02 14:10 下午 回應:
@heresy 谢谢了
我人怒了上帝 於 2012/03/25 11:31 上午 回應:
请问裁剪(cropping)支持kinect摄像头吗?能看看我的代码不,看哪里出错了?
#include "stdafx.h"
#include
#include
#include
#include
#include "opencv/cv.h"
#include "opencv/highgui.h"

using namespace std;
using namespace cv;

void CheckOpenNIError( XnStatus result, string status )
{
if( result != XN_STATUS_OK )
cerr
我惹怒了上帝 於 2012/03/25 11:33 上午 回應:
xn::Context m_context;
xn:很高興epthGenerator m_depth;
xn::ImageGenerator m_image;
XnStatus l_status = XN_STATUS_OK;

l_status = m_image.SetIntProperty("InputFormat", 0);

XnMapOutputMode m_depth_mode;
//Set it to VGA maps at 30 FPS
m_depth_mode.nXRes = XN_VGA_X_RES;
m_depth_mode.nYRes = XN_VGA_Y_RES;
m_depth_mode.nFPS = 30;
XnMapOutputMode l_frame_mode;
l_frame_mode.nXRes = XN_VGA_X_RES;
l_frame_mode.nYRes = XN_VGA_Y_RES;
l_frame_mode.nFPS = 30;
// Initialize context object
l_status = m_context.Init();
if(l_status)
{ printf("Error:%s", xnGetStatusString(l_status));
return (l_status==XN_STATUS_OK);
}
// Create a DepthGenerator node
l_status = m_depth.Create(m_context);
if(l_status)
{ printf("Error : %s", xnGetStatusString(l_status));
return (l_status==XN_STATUS_OK);
}
// Create a ImageGenerator node
l_status = m_image.Create(m_context);
if(l_status)
{ printf("Error : %s", xnGetStatusString(l_status));
return (l_status==XN_STATUS_OK);
}
// set frame rate and image size
l_status = m_depth.SetMapOutputMode(m_depth_mode);
if(l_status)
{ printf("Error : %s", xnGetStatusString(l_status));
return (l_status==XN_STATUS_OK);
}
// set frame rate and image size
l_status = m_image.SetMapOutputMode(l_frame_mode);
if(l_status)
{ printf("Error : %s", xnGetStatusString(l_status));
return (l_status==XN_STATUS_OK);
}
// set frame format
l_status =m_image.SetPixelFormat(XN_PIXEL_FORMAT_RGB24);
if(l_status)
{ printf("Error : %s", xnGetStatusString(l_status));
return (l_status==XN_STATUS_OK);
}
// Cropping
XnCropping pCropping;
pCropping.bEnabled=true;
pCropping.nXOffset=0;
pCropping.nYOffset=0;
pCropping.nXSize=640;
pCropping.nYSize=480;
if(!m_image.IsCapabilitySupported(XN_CAPABILITY_CROPPING))
{ printf("Stream does not support cropping!");
return false;
}
l_status = m_image.GetCroppingCap().SetCropping(pCropping);
if(l_status)
{ printf("Failed to set cropping: %s",xnGetStatusString(l_status));
return false;
}
// Make it start generating data
l_status = m_context.StartGeneratingAll();
if(l_status)
{ printf("Error : %s", xnGetStatusString(l_status));
return (l_status==XN_STATUS_OK);
}
// Get pixel size
XnDouble m_pixel_size;
l_status=m_depth.GetRealProperty("ZPPS",m_pixel_size);
if(l_status)
{ printf("Error : %s", xnGetStatusString(l_status));
return (l_status==XN_STATUS_OK);
}
// Get virtual plane distance
XnUInt64 m_virtual_plane_dist;
l_status=m_depth.GetIntProperty("ZPD",m_virtual_plane_dist);
if(l_status)
{ printf("Error : %s", xnGetStatusString(l_status));
return (l_status==XN_STATUS_OK);
}
char key=0;
xn:很高興epthMetaData depthMD;
xn::ImageMetaData imageMD;
//OpenCV
IplImage* imgRGB8u=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
IplImage* imageShow=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
cvNamedWindow("image",1);
while( key!=27 )
{
//get meta data
m_image.GetMetaData(imageMD);
//OpenCV output
memcpy(imgRGB8u->imageData,imageMD.Data(),640*480*3);
cvCvtColor(imgRGB8u,imageShow,CV_RGB2BGR);
cvShowImage("image",imageShow);
key=cvWaitKey(20);
}
作者作者heresy 於 2012/03/26 09:07 上午 回應:
to 我惹怒了上帝
抱歉,Heresy 這邊沒有使用過 cropping 的功能,也沒有 OpenCV 的環境,所以不確定是否可以正常使用。
丁 於 2012/07/08 22:56 下午 回應:
請問一下heresy

請問利用openni開發到底需要安裝哪些軟體?
目前我所知的需要安裝
1.openni
2.sensorkinect
3.nite
目前這三個軟體都有安裝,但開一些其他人的範例,都會發生錯誤。
------------------------------------------------------------
----------------------另外openCV、openGL、unity,這三種東西都是需要另外裝嗎?

不好意思問這麼多問題,爬一些文章這麼久了,對於openni的開發環境還是存在很多疑問。
作者作者heresy 於 2012/07/09 08:44 上午 回應:
to 丁

請參考:
http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&
SUB_ID=6&PAPER_ID=317

基本上,如果你是使用 Kinect,那的確只需要你說的那三樣。
其他的函式庫則是視需要而定,並非一定要的。
JavaCS3 於 2012/10/15 20:46 下午 回應:
疑惑我最近使用kinect的时候碰见一个问题,就是总是出现timeout error 而且去看sample 也出现timeout 然后程序就崩溃了~。我一开始安装的时候也碰到这个问题,但是后来好了一阵子。直到昨天开机的时候卡死了,重启后再去用kine
ct又出现timeout了。请问有什么解决方法么?
作者作者heresy 於 2012/10/16 08:41 上午 回應:
to JavaCS3

抱歉,Heresy 沒碰過這樣的問題。只能建議你試試看換一台電腦做測試?
JavaCS3 於 2012/10/16 16:22 下午 回應:
震驚我去网上搜索这timeout的问题还算普遍,但是目前没有什么好的解决方法!
不过还好今天又正常了!
yulinfenfei 於 2012/10/26 10:01 上午 回應:
Heresy,你好,我想请问下,如果我用kinect提取出某一物体的质心后,能够获取它的三维坐标吗?
作者作者heresy 於 2012/10/26 10:39 上午 回應:
你只要知道他在影像上的座標,就可以參考深度圖取得他的三度空間位置。
yulinfenfei 於 2012/10/26 11:02 上午 回應:
不好意思,再打扰一下,kinect可以将场景中的运动物体分割出来吗,还是它只可以识别人体?
yulinfenfei 於 2012/10/26 11:07 上午 回應:
Heresy,我上面的意思就是说,我想从彩色影像中分割出运动物体,然后获取到这个目标的质心,然后将它映射到深度影像中,获
取到该点的三维坐标,我不知道OpenNI可不可以这样实现?
作者作者heresy 於 2012/10/26 12:13 下午 回應:
to yulinfenfei

OpenNI 本身只有提供追蹤人體的功能,並不能拿來追蹤一般物體。
不過這功能應該可以透過和其他函式庫(例如 OpenCV)合併使用來做到。
yulinfenfei 於 2012/10/26 13:10 下午 回應:
嗯,谢谢heresy哈
yulinfenfei 於 2012/10/29 15:28 下午 回應:
heresy,您好,我取得了影像数据中的某一点坐标了,但是我要怎样将它映射到深度图中呢,也就是说我怎样将这一点与深度图中
的对应点联系起来,从而得到该点的三维坐标呢?
作者作者heresy 於 2012/10/30 08:51 上午 回應:
to yulinfenfei

你如果有使用 AlternativeViewPointCapability 來做彩色影像和深度影像的位置校正的話,那彩色影像上的 x, y 就會直接對應到深度影像的同一個像素。
http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&
SUB_ID=1&PAPER_ID=216


在這情況下,只要把 Z 的直從深度影像取出來,就是 OpenNI 投影座標系統的點位了。
yulinfenfei 於 2012/10/30 10:15 上午 回應:
嗯,谢谢您哈
xijingming 於 2012/11/06 16:04 下午 回應:
看了您大部分文章,极其感谢。请教您,我想了解有没有关于场景分析的使用介绍或者demo,blog中这方面好像没有涉及。
作者作者heresy 於 2012/11/06 17:23 下午 回應:
to xijingming
Heresy 的確沒有針對他特別寫過。
因為實際上,Heresy 覺得他比較特別的功能,也就只有做地板偵測的功能而已。
xijingming 於 2012/11/06 20:28 下午 回應:
很感谢您这么快的回复,我在找这方面的资料,而且openni里面也没有这方面的demo,不知道您是否有相关资料的推荐,表示
非常感激!
作者作者heresy 於 2012/11/07 09:26 上午 回應:
to xijingming
不知道你是要什麼功能?
NITE 的官方範例裡面,應該就有一個 SceneAnalysis 的範例了?
xijingming 於 2012/11/07 16:50 下午 回應:
我想用里面的地面检测,
我看了一些资料,采用如下写法
xn::Context xContext;
xn::SceneAnalyzer xScene;
XnStatus result;
result=xContext.Init();
if (result!=XN_STATUS_OK)
AfxMessageBox(_T("xContext init failed!"),MB_YESNO);
result=xScene.Create( xContext );
if (result!=XN_STATUS_OK)
AfxMessageBox(_T("xScene init failed!"),MB_YESNO);

xscene的create,返还的result 不是ok,请问,这里面的错误,非常感谢

作者作者heresy 於 2012/11/08 09:28 上午 回應:
to xijingming

1. 建議請以 xnGetStatusString() 來取得錯誤的說明文字,不要只是單純判斷是否正確。

2. 建議在前面先建立出 Depth Generator 再試試看。
xijingming 於 2012/11/09 16:39 下午 回應:
这个跟驱动的版本有关系,包括控制motor,我把驱动更新到高版本就可以了,但是求出来的数据感觉不太正确,还在继续研究中
空山新雨 於 2012/11/10 22:04 下午 回應:
你好,淘宝上700左右说能进行pc开发的Kinect,买过来能和openni连接吗?为什么有些for windows的价格这么高?
作者作者heresy 於 2012/11/13 08:33 上午 回應:
to 空山新雨
抱歉,Heresy 不確定你說的硬體是哪款。
不過,目前 OpenNI 能支援的硬體,應該只有 ASUS 和 Microsoft 的產品。
星星 於 2013/02/16 17:11 下午 回應:
作者您好
我想請問一下
OpenNI校正RGB攝影機以及深度攝影機視角
他有什麼缺點嗎?
因為網路上還是有許多PAPER在解決校正視角的問題
他是官方提供的解決方法嗎?
作者作者heresy 於 2013/02/18 09:54 上午 回應:
to 星星

抱歉,Heresy 沒有做這方面的研究。
雖然內建的視角校正在某些時候不是很精確,但是基本上一般應該是夠用才對。
天空 於 2013/04/21 20:56 下午 回應:
文章很好,不知道openni要怎么配置呢?
作者作者heresy 於 2013/04/22 08:59 上午 回應:
to 天空

不確定你的問題是什麼?不過如果是想知道怎麼開始開發 OpenNI 程式的話,請參考:
http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&
SUB_ID=1&PAPER_ID=215

-- TOP --

我要回應
* 身份  訪客 (暱稱:)
 本篇文章作者 (帳號:密碼:)
* 內容      
很高興 悲傷 震驚 疑惑 大笑 發瘋 傷心
* 留言密碼 (請輸入下方圖片中去除前、後位數的數字,共五碼。)
說明 1. * 表示必填欄位。
2. 不支援HTML Tag。
   

-- TOP --

© Visualization and Interactive Media Laboratory of NCHC, 2007 - 2021, All Rights Reserved. Contact E-mail