zoukankan      html  css  js  c++  java
  • Kinect+OpenNI学习笔记之5(使用OpenNI自带的类进行简单手势识别)

      

      前言

      因为OpenNI可以获取到kinect的深度信息,而深度信息在手势识别中有很大用处,因此本文就来使用OpenNI自带的类来做简单的手势识别。识别的动作为4种,挥手,手移动,举手,往前推手。通过后面的实验可以发现,其实提供的类的效果非常不好。

      开发环境:QtCreator2.5.1+OpenNI1.5.4.0+Qt4.8.2+OpenCV2.4.2

      实验说明

      跟手势相关的是GestureGenerator这个类,它的初始化过程和depth_metadata,image_metadata都一样,因此首先在上2篇文章的COpenNI类中增加一个public类对象GestureGenerator gesture_generator;为什么不放在private里呢?因为我们的COpenNI对象需要调用这个变量来设置手势获取的一些属性,比如手势识别的种类等,总之就是这个变量外部需要能够访问得到,因此这里我将其放在public里面。另外在COpenNI类的Init()函数中需要加入下面的代码:

    status = gesture_generator.Create(context);
    
            if(CheckError("Create gesture generator error!")) {
    
                return false;
    
            }
    
            /*添加手势识别的种类*/
    
            gesture_generator.AddGesture("Wave", NULL);
    
            gesture_generator.AddGesture("click", NULL);
    
            gesture_generator.AddGesture("RaiseHand", NULL);
    
            gesture_generator.AddGesture("MovingHand", NULL);

      OpenNI进行手势识别的方式是采用函数回调,即如果一个手势发生了或者正在发生时可以触发相应的回调函数,从而去执行回调函数,这有点类似于Qt中的信号与槽的关系。在OpenNI中设置回调函数的原型为:

      XnStatus RegisterGestureCallbacks(GestureRecognized RecognizedCB, GestureProgress ProgressCB, void* pCookie, XnCallbackHandle& hCallback);

      其中前2个参数为回调函数,第一个回调函数表示手部某个动作已经执行完毕,第二个参数表示收部某个动作正在执行;参数三为一个空指针,即可以指向任何数据类型的指针,其作用为给回调函数当额外的参数使用;参数四为回调函数的处理函数,用来记录和管理回调函数的。参数三在本实验中设置为NULL,参数四实际上本实验中也没有用到。

    上面2个回调函数的名称可以自定义,但是这2个函数参数的个数和类型不能改变,这2个回调函数的参数个数都为5,但是其类型有些不同,具体的可以参考后面提供的代码。

      由于在程序中添加了4种动作的捕捉,所以打算在检测到某个手势动作时,在窗口显示栏的图片上添加相应的手势动作文字提示。很明显,只有当手势检测到时才能在图片上添加文字,该部分在回调函数中实现。但是如果我们单独在回调函数中给图片添加相应的文字,然后在主程序中显示图片,则因为回调函数一结束完就回到了主函数的while循环中,而这时图片的内容已经更新了(即有文字的图片被重新覆盖了),因此人眼一瞬间看不到有文字提示的图片。最后个人的解决方法是用一个标志来表示检测到了某个手势动作,如果检测到了则显示存储下来的有文字的图片,反正,显示正常的图片。本程序提供的图片为深度图。

     

     

      实验结果

      举手的显示结果如下:

      

       其实从本人的实验过程来看,大部分的手势动作都被检测为举手RaiseHand,少部分为挥手Wave,其它的基本上没出现过。说明OpenNI自带的手势识别类的功能不是很强。

     

     

      实验主要部分代码及注释(附录有实验工程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;
            }
            status = gesture_generator.Create(context);
            if(CheckError("Create gesture generator error!")) {
                return false;
            }
            /*添加手势识别的种类*/
            gesture_generator.AddGesture("Wave", NULL);
            gesture_generator.AddGesture("click", NULL);
            gesture_generator.AddGesture("RaiseHand", NULL);
            gesture_generator.AddGesture("MovingHand", NULL);
            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;
        GestureGenerator gesture_generator;//外部要对其进行回调函数的设置,因此将它设为public类型
    
    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;
    
    Mat depth_image;
    Mat depth_image_result;//深度结果图,且在该图上显示手势动作的类型
    COpenNI openni;
    bool test_flag = false;
    
    // callback function for gesture recognized
    //回调函数,该函数的函数名字可以随便取,但是其参数的格式必须不能改变
    //这里该函数的作用是表示上面4种手势发生完成后调用
    void  XN_CALLBACK_TYPE  GRecognized ( xn::GestureGenerator &generator,
                                        const XnChar *strGesture,
                                        const  XnPoint3D *pIDPosition,
                                        const  XnPoint3D *pEndPosition,
                                        void *pCookie )
    {
        depth_image_result = depth_image.clone();
        putText(depth_image_result, strGesture, Point(50, 150), 3, 0.8, Scalar(255, 0, 0), 2 );
        test_flag = true;
    }
    
    // callback function for gesture progress
    //该函数表示上面4种手势某一种正在发生时调用
    void  XN_CALLBACK_TYPE  GProgress ( xn::GestureGenerator &generator,
                                      const XnChar *strGesture,
                                      const  XnPoint3D *pPosition,
                                     XnFloat fProgress,
                                     void *pCookie )
    {
        ;
    }
    
    int main (int argc, char **argv)
    {
    
        if(!openni.Initial())
            return 1;
        XnCallbackHandle handle;
        openni.gesture_generator.RegisterGestureCallbacks(GRecognized, GProgress, NULL, handle);
        if(!openni.Start())
            return 1;
        namedWindow("depth image", CV_WINDOW_AUTOSIZE);
        putText(depth_image, "YES!", Point(50, 150), 3, 0.8, Scalar(255, 0, 0), 2 );
        while(1) {
            if(!openni.UpdateData()) {
                return 1;
            }
            /*获取并显示深度图像,且这2句代码不能放在回调函数中调用,否则后面的imshow函数会因为执行时找不到图片(因为此时回调函数不一定执行了)而报错*/
            Mat depth_image_src(openni.depth_metadata.YRes(), openni.depth_metadata.XRes(),
                                CV_16UC1, (char *)openni.depth_metadata.Data());//因为kinect获取到的深度图像实际上是无符号的16位数据
            depth_image_src.convertTo(depth_image, CV_8U, 255.0/8000);
    
            if(!test_flag)
                imshow("depth image", depth_image);
            else
                imshow("depth image", depth_image_result);
            waitKey(30);
            test_flag = false;
        }
    
    }

     

      错误总结

      如果用Qt的控制台建立程序,运行程序时出现下面的错误提示:

      

      这是因为控制台程序不能使用Qt的界面(本程序中使用了QMessageBox),因此需要在工程pro的代码中把QT –  gui给去掉,否则会报类似的这种错误。

      如果是在OpenCV中出现如下错误:

      

      则表示是imshow函数需要还来不及显示完成就被其它的函数给中断了,这可能在回调函数中出现这种情况。

     

      

      实验总结

      通过本次实验对OpenNI自带的手势识别类的使用有了初步的了解。

     

     

      参考资料:

        OpenNI 的手势侦测

     

     

      附录:实验工程code下载

     

     

     

  • 相关阅读:
    苹果推送通知服务(APNs)编程
    Mac svn命令 linux同样适用
    IOS多线程(NSThread,NSOperation,Grand Central Dispatch)
    iOS7新特性之二维码生成于读取
    Socket即时通讯小实例
    iOS内置加速计(UIAccelerometer/CoreMotion)
    iOS设计模式----委托模式
    NSXMLParser详解
    Core Foundation 框架
    UIView和CALayer的区别
  • 原文地址:https://www.cnblogs.com/tornadomeet/p/2710094.html
Copyright © 2011-2022 走看看