Kinect+OpenNI學習筆記之4(OpenNI獲取的圖像結合OpenCV顯示)


 

  前言

  本文來結合下opencv的highgui功能顯示kinect采集得來的顏色圖和深度圖。本來在opencv中自帶了VideoCapture類的,使用該類可以直接驅動kinect設備,具體的可以參考下面的文章:http://blog.csdn.net/moc062066/article/details/6949910,也可以參考opencv提供的官方文檔:http://docs.opencv.org/doc/user_guide/ug_highgui.html。這種方法用起來非常簡單,不需要考慮OpenNI的驅動過程,有點像傻瓜式的操作。不過本人在使用該種方法時kinect一直驅動不成功,即使用opencv的VideoCapture類來捕捉Kinect設備的數據,一直是打不開的,即驅動不成功。但是kinect設備已經連接上了,且能運行openni中的sample,說明kinect的硬件驅動是沒問題的,應該是opencv這個類的bug,網上很多人都碰到了該情況。

  所以還是使用前面2篇博文介紹的,自己用OpenNI寫驅動,這樣可以更深刻的對OpenNI這個庫靈活運用。

  開發環境:QtCreator2.5.1+OpenNI1.5.4.0+Qt4.8.2+OpenCV2.4.2

 

  實驗說明

  在用OpenCV顯示OpenNI的數據時,先來了解下Kinect獲取到的深度信息的一些特點,Heresy的文章:Kinect + OpenNI 的深度值 介紹得比較通俗易懂。下面是個人覺得kinect深度信息比較重要的地方:Kinect官方推薦的使用距離為1.2m到3.6m之間。其中1.2m時的精度為3mm,3.2米的時候精度越為3cm。隨着距離越來越遠,其檢測到的精度也越來越小。精度最小為1mm,大概是距離50cm時,不過此時的點數量比較少,也不穩定,因此官方沒有推薦使用這個時候的距離。

  另外還需要注意OpenNI中表示深度像素的格式為XnDepthPixel,實際上是單一channel的16位正整數,因此如果使用OpenCV來存儲時,需要設定格式為CV_16UC1。因此其范圍是0~65536,不過期最大的深度只能感應到10000,所以我們需要將其歸一化到一個比較好的范圍內。

  本文使用的是上一篇博文:Kinect+OpenNI學習筆記之3(獲取kinect的數據並在Qt中顯示的類的設計) 中用到的類COpenNI,該類可以方便的驅動kinect,並將獲得的色彩信息和深度信息保存在共有變量中,提供其對象來調用。主函數中使用OpenCV庫來創建窗口,且將Kinect獲到的數據轉換成OpenCV的格式,然后在創建的窗口中顯示。同時也對深度圖像和顏色圖像進行了canny邊緣檢測並顯示出來比較。

 

  實驗結果

  本實驗顯示4幅圖像,分別為顏色原圖及其canny邊緣檢測圖,深度原圖及其canny邊緣檢測圖。結果截圖部分圖如下:

 

 

  實驗主要部分代碼及注釋(附錄有實驗工程code下載鏈接地址):

copenni.cpp:

#include <XnCppWrapper.h>
#include <QtGui/QtGui>
#include <iostream>

using namespace xn;
using namespace std;

class COpenNI
{
public:
    ~COpenNI() {
        context.Release();//釋放空間
    }
    bool Initial() {
        //初始化
        status = context.Init();
        if(CheckError("Context initial failed!")) {
            return false;
        }
        context.SetGlobalMirror(true);//設置鏡像
        //產生圖片node
        status = image_generator.Create(context);
        if(CheckError("Create image generator  error!")) {
            return false;
        }
        //產生深度node
        status = depth_generator.Create(context);
        if(CheckError("Create depth generator  error!")) {
            return false;
        }
        //視角校正
        status = depth_generator.GetAlternativeViewPointCap().SetViewPoint(image_generator);
        if(CheckError("Can't set the alternative view point on depth generator")) {
            return false;
        }

        return true;

    }

    bool Start() {
        status = context.StartGeneratingAll();
        if(CheckError("Start generating error!")) {
            return false;
        }
        return true;
    }

    bool UpdateData() {
        status = context.WaitNoneUpdateAll();
        if(CheckError("Update date error!")) {
            return false;
        }
        //獲取數據
        image_generator.GetMetaData(image_metadata);
        depth_generator.GetMetaData(depth_metadata);

        return true;
    }

public:
    DepthMetaData depth_metadata;
    ImageMetaData image_metadata;

private:
    //該函數返回真代表出現了錯誤,返回假代表正確
    bool CheckError(const char* error) {
        if(status != XN_STATUS_OK ) {
            QMessageBox::critical(NULL, error, xnGetStatusString(status));
            cerr << error << ": " << xnGetStatusString( status ) << endl;
            return true;
        }
        return false;
    }

private:
    XnStatus    status;
    Context     context;
    DepthGenerator  depth_generator;
    ImageGenerator  image_generator;
};

 

main.cpp:

#include <QCoreApplication>

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/core/core.hpp>
#include "copenni.cpp"

#include <iostream>

using namespace cv;
using namespace xn;

int main (int argc, char **argv)
{
    COpenNI openni;
    if(!openni.Initial())
        return 1;

    namedWindow("color image", CV_WINDOW_AUTOSIZE);
    namedWindow("color edge detect", CV_WINDOW_AUTOSIZE);
    namedWindow("depth image", CV_WINDOW_AUTOSIZE);
    namedWindow("depth edge detect", CV_WINDOW_AUTOSIZE);

    if(!openni.Start())
        return 1;
    while(1) {
        if(!openni.UpdateData()) {
            return 1;
        }
        /*獲取並顯示色彩圖像*/
        Mat color_image_src(openni.image_metadata.YRes(), openni.image_metadata.XRes(),
                            CV_8UC3, (char *)openni.image_metadata.Data());
        Mat color_image;
        cvtColor(color_image_src, color_image, CV_RGB2BGR);
        imshow("color image", color_image);

        /*對色彩圖像進行canny邊緣檢測並顯示*/
        Mat color_image_gray, color_image_edge;
        cvtColor(color_image_src, color_image_gray, CV_RGB2GRAY);//因為在進行邊緣檢測的時候只能使用灰度圖像
        Canny(color_image_gray, color_image_edge, 5, 100);
        imshow("color edge detect", color_image_edge);

        /*獲取並顯示深度圖像*/
        Mat depth_image_src(openni.depth_metadata.YRes(), openni.depth_metadata.XRes(),
                            CV_16UC1, (char *)openni.depth_metadata.Data());//因為kinect獲取到的深度圖像實際上是無符號的16位數據
        Mat depth_image, depth_image_edge;
        depth_image_src.convertTo(depth_image, CV_8U, 255.0/8000);
        imshow("depth image", depth_image);

        /*計算深度圖像的canny邊緣並顯示*/
        Canny(depth_image, depth_image_edge, 5, 100);
        imshow("depth edge detect", depth_image_edge);
        waitKey(30);

    }

}

 

 

  總結:本實驗將OpenNI驅動的Kinect數據轉換成OpenCV中方便處理的格式,達到了將OpenNI和OpenCV兩者相結合的目的。

 

 

  參考資料:

     Kinect+OpenNI學習筆記之3(獲取kinect的數據並在Qt中顯示的類的設計)

     opencv2.3讀取kinect深度信息和彩色圖像

     Kinect + OpenNI 的深度值

     OpenNI + OpenCV

 

 

  附錄: 實驗工程code下載

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM