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

| | 40 Comments| 11:39
Categories:

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

40 thoughts on “Kinect 的軟體開發方案:OpenNI 簡介”

  1. 你好,你的文章對我大有裨益,不過可不可以介紹一下kinect語音識別方面的應用。謝謝!

  2. 你好~想問一下大大~~因為我的英文不大好 = = 但我想好好看完《OpenNI User Guide》裡面提供的資訊~~不知道有沒有中文的可以看 = =

  3. :D学习了!另,有没有针对MAC的openNI使用方法的介绍?

  4. heresy您好,我是新手,现在在做一个KINECT的开发。 我想问一下您:使用OPENNI所获得的KINECT侦测到的数据如何用呢? 比如说,我想使用KINECT作为遥控器来控制灯的亮灭。应该如何使用OPENNI提取到的数据呢?能不能大概的说说、谢谢

  5. @Chocolate 基本上這主要取決於你要怎麼定義控制的方法。最簡單的方法,就是直接使用 NITE 所定義的手勢、並在偵測到指定的手勢的時候,去做你要做的動作。不然,就是要自己去定義其他的判斷條件,來做是否要執行的檢查了。

  6. 请问裁剪(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

  7. xn::Context m_context;
    xn::DepthGenerator 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::DepthMetaData 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);
    }

  8. to 我惹怒了上帝
    抱歉,Heresy 這邊沒有使用過 cropping 的功能,也沒有 OpenCV 的環境,所以不確定是否可以正常使用。

  9. 請問一下heresy

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

    不好意思問這麼多問題,爬一些文章這麼久了,對於openni的開發環境還是存在很多疑問。

  10. :per:我最近使用kinect的时候碰见一个问题,就是总是出现timeout error 而且去看sample 也出现timeout 然后程序就崩溃了~。我一开始安装的时候也碰到这个问题,但是后来好了一阵子。直到昨天开机的时候卡死了,重启后再去用kinect又出现timeout了。请问有什么解决方法么?

  11. to JavaCS3

    抱歉,Heresy 沒碰過這樣的問題。只能建議你試試看換一台電腦做測試?

  12. :o我去网上搜索这timeout的问题还算普遍,但是目前没有什么好的解决方法!
    不过还好今天又正常了!

  13. Heresy,你好,我想请问下,如果我用kinect提取出某一物体的质心后,能够获取它的三维坐标吗?

  14. 你只要知道他在影像上的座標,就可以參考深度圖取得他的三度空間位置。

  15. 不好意思,再打扰一下,kinect可以将场景中的运动物体分割出来吗,还是它只可以识别人体?

  16. Heresy,我上面的意思就是说,我想从彩色影像中分割出运动物体,然后获取到这个目标的质心,然后将它映射到深度影像中,获取到该点的三维坐标,我不知道OpenNI可不可以这样实现?

  17. to yulinfenfei

    OpenNI 本身只有提供追蹤人體的功能,並不能拿來追蹤一般物體。
    不過這功能應該可以透過和其他函式庫(例如 OpenCV)合併使用來做到。

  18. heresy,您好,我取得了影像数据中的某一点坐标了,但是我要怎样将它映射到深度图中呢,也就是说我怎样将这一点与深度图中的对应点联系起来,从而得到该点的三维坐标呢?

  19. 看了您大部分文章,极其感谢。请教您,我想了解有没有关于场景分析的使用介绍或者demo,blog中这方面好像没有涉及。

  20. to xijingming
    Heresy 的確沒有針對他特別寫過。
    因為實際上,Heresy 覺得他比較特別的功能,也就只有做地板偵測的功能而已。

  21. 很感谢您这么快的回复,我在找这方面的资料,而且openni里面也没有这方面的demo,不知道您是否有相关资料的推荐,表示非常感激!

  22. to xijingming
    不知道你是要什麼功能?
    NITE 的官方範例裡面,應該就有一個 SceneAnalysis 的範例了?

  23. 我想用里面的地面检测,
    我看了一些资料,采用如下写法
    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,请问,这里面的错误,非常感谢

  24. to xijingming

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

    2. 建議在前面先建立出 Depth Generator 再試試看。

  25. 这个跟驱动的版本有关系,包括控制motor,我把驱动更新到高版本就可以了,但是求出来的数据感觉不太正确,还在继续研究中

  26. 你好,淘宝上700左右说能进行pc开发的Kinect,买过来能和openni连接吗?为什么有些for windows的价格这么高?

  27. to 空山新雨
    抱歉,Heresy 不確定你說的硬體是哪款。
    不過,目前 OpenNI 能支援的硬體,應該只有 ASUS 和 Microsoft 的產品。

  28. 作者您好
    我想請問一下
    OpenNI校正RGB攝影機以及深度攝影機視角
    他有什麼缺點嗎?
    因為網路上還是有許多PAPER在解決校正視角的問題
    他是官方提供的解決方法嗎?

  29. to 星星

    抱歉,Heresy 沒有做這方面的研究。
    雖然內建的視角校正在某些時候不是很精確,但是基本上一般應該是夠用才對。

發佈回覆給「heresy」的留言 取消回覆

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *