利用KINECT+OPENCV检测手势的演示程序

来源:互联网 发布:数控车床锥度编程实例 编辑:程序博客网 时间:2024/04/25 08:43

转自:http://blog.csdn.net/firefight/article/details/6304050

2011-4-10 增加结果图片,更新代码,将模板改为6个(0-5)

 

1,原理:读入KINECT深度数据,转换为二值图像,找到轮廓,与轮廓模板比较,找到HU矩阵最小的为匹配结果

2,基础:OPENNI, OPENCV2.2 以及http://blog.163.com/gz_ricky/blog/static/182049118201122311118325/
的例程基础上修改

3,结果:仅仅用于演示利用OPENCV+OPENNI编程,对结果精度,处理速度等没有优化,仅供参考

 

对0,1和5的比较比较准确

 

废话少说,一切都在代码中

[cpp] view plaincopy
  1. // KinectOpenCVTest.cpp : 定义控制台应用程序的入口点。  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6.   
  7. #include <stdlib.h>  
  8. #include <iostream>  
  9. #include <string>  
  10. #include <XnCppWrapper.h>  
  11. #include <opencv2/opencv.hpp>  
  12.   
  13. //#include "opencv/cv.h"  
  14. //#include "opencv/highgui.h"  
  15. using namespace std;  
  16. using namespace cv;  
  17.   
  18. #define SAMPLE_XML_PATH "../../Data/SamplesConfig.xml"  
  19.   
  20. //全局模板轮廓  
  21. vector<vector<Point>> g_TemplateContours;  
  22.   
  23. //模板个数  
  24. int g_handTNum = 6;  
  25.   
  26. void CheckOpenNIError( XnStatus eResult, string sStatus )  
  27. {   
  28.     if( eResult != XN_STATUS_OK )   
  29.     {  
  30.         cerr << sStatus << " Error: " << xnGetStatusString( eResult ) << endl;  
  31.         return;       
  32.     }  
  33. }  
  34.   
  35. //载入模板的轮廓  
  36. void init_hand_template()  
  37. {  
  38.     //int handTNum = 10;  
  39.     string temp = "HandTemplate/";  
  40.       
  41.     int i = 0;  
  42.   
  43.   
  44.     for(i=0; i<g_handTNum; i++)  
  45.     {  
  46.         stringstream ss;  
  47.         ss << i << ".bmp";  
  48.   
  49.         string fileName = temp + ss.str();   
  50.   
  51.         //读入灰度图像  
  52.         Mat src = imread(fileName, 0);  
  53.   
  54.         if(!src.data)  
  55.         {  
  56.             printf("未找到文件: %s/n", fileName);  
  57.             continue;  
  58.         }  
  59.   
  60.         vector<vector<Point>> contours;  
  61.         vector<Vec4i> hierarchy;  
  62.   
  63.         findContours(src, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);  
  64.         //findContours(src, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);  
  65.   
  66.         g_TemplateContours.push_back(contours[0]);  
  67.     }  
  68. }  
  69.   
  70. //模板匹配手  
  71. int hand_template_match(Mat& hand)  
  72. {  
  73.     //int handTNum = 10;  
  74.     int minId = -1;  
  75.     double minHu = 1;  
  76.       
  77.     double hu;  
  78.     int method = CV_CONTOURS_MATCH_I1;  
  79.       
  80.     //match_num = 0;  
  81.   
  82.     for(int i=0; i<g_handTNum; i++){  
  83.   
  84.         Mat temp(g_TemplateContours.at(i));  
  85.         hu = matchShapes(temp, hand, method, 0);  
  86.           
  87.         //找到hu矩最小的模板  
  88.         if(hu < minHu){  
  89.             minHu = hu;  
  90.             minId = i;  
  91.         }  
  92.           
  93.         //printf("%f ", hu);  
  94.     }  
  95.       
  96.     //显示匹配结果  
  97.     int Hmatch_value = 25;//模板匹配系数  
  98.   
  99.     if(minHu<((double)Hmatch_value)/100)  
  100.         return minId;  
  101.     else  
  102.         return -1;  
  103. }  
  104.   
  105. void findHand(Mat& src, Mat& dst)  
  106. {  
  107.     vector<vector<Point>> contours;  
  108.     vector<Vec4i> hierarchy;  
  109.   
  110.     //找到外部轮廓  
  111.     //findContours(src, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);  
  112.     findContours(src, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); //CV_CHAIN_APPROX_NONE);  
  113.     //findContours(src, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);  
  114.   
  115.     Mat dst_r = Mat::zeros(src.rows, src.cols, CV_8UC3);  
  116.     dst_r.copyTo(dst);  
  117.   
  118.     // iterate through all the top-level contours,  
  119.     // draw each connected component with its own random color  
  120.     int idx = 0;  
  121.     double maxArea = 0.0;  
  122.     int maxId = -1;  
  123.   
  124.     for(unsigned int i = 0; i<contours.size(); i++)  
  125.     {  
  126.         Mat temp(contours.at(i));  
  127.         double area = fabs(contourArea(temp));  
  128.         if(area > maxArea)  
  129.         {  
  130.             maxId = i;  
  131.             maxArea = area;  
  132.         }  
  133.     }  
  134.   
  135.     //for( ; idx >= 0; idx = hierarchy[idx][0] )  
  136.     //{  
  137.     //  //Scalar color( rand()&255, rand()&255, rand()&255 );  
  138.     //  //drawContours(dst, contours, idx, color, CV_FILLED, 8, hierarchy );  
  139.   
  140.     //  double area = contourArea(contours.at(idx));  
  141.     //  if(area > maxArea)  
  142.     //  {  
  143.     //      maxId = idx;  
  144.     //      maxArea = area;  
  145.     //  }  
  146.     //}  
  147.   
  148.     //显示最大轮廓外形,以及最佳匹配的模板ID  
  149.     if(contours.size() > 0)  
  150.     {  
  151.         Scalar color(0, 255, 255 );  
  152.         drawContours(dst, contours, maxId, color);  
  153.   
  154.         Mat hand(contours.at(maxId));  
  155.         int value = hand_template_match(hand);  
  156.   
  157.         if(value >= 0)  
  158.         {  
  159.             Scalar templateColor(255, 0, 255 );  
  160.             drawContours(dst, g_TemplateContours, value, templateColor);  
  161.   
  162.             printf("Match %d /r/n", value);  
  163.   
  164.             stringstream ss;  
  165.             ss << "Match " << value;  
  166.             string text = ss.str();  
  167.             putText(dst, text, Point(300, 30), FONT_HERSHEY_SIMPLEX, 1.0, templateColor);  
  168.         }  
  169.     }  
  170. }  
  171.   
  172.   
  173. int HandDetect()  
  174. {  
  175.     init_hand_template();  
  176.   
  177.     XnStatus eResult = XN_STATUS_OK;    
  178.   
  179.     // 1. initial val  
  180.     xn::DepthMetaData m_DepthMD;  
  181.     xn::ImageMetaData m_ImageMD;  
  182.   
  183.     // for opencv Mat  
  184.     Mat  m_depth16u( 480,640,CV_16UC1);  
  185.     Mat  m_rgb8u( 480,640,CV_8UC3);  
  186.     Mat  m_DepthShow( 480,640,CV_8UC1);  
  187.     Mat  m_ImageShow( 480,640,CV_8UC3);  
  188.   
  189.     Mat  m_DepthThreshShow( 480,640,CV_8UC1);  
  190.     Mat  m_HandShow( 480,640,CV_8UC3);  
  191.   
  192.     //cvNamedWindow("depth");  
  193.     //cvNamedWindow("image");  
  194.     //cvNamedWindow("depthThresh");  
  195.   
  196.     char key=0;  
  197.   
  198.     // 2. initial context   
  199.     xn::Context mContext;   
  200.   
  201.     eResult = mContext.Init();   
  202.   
  203.     //xn::EnumerationErrors errors;  
  204.     //eResult = mContext.InitFromXmlFile(SAMPLE_XML_PATH, &errors);  
  205.   
  206.     CheckOpenNIError( eResult, "initialize context" );    
  207.       
  208.     //Set mirror  
  209.     mContext.SetGlobalMirror(!mContext.GetGlobalMirror());  
  210.   
  211.     // 3. create depth generator    
  212.     xn::DepthGenerator mDepthGenerator;    
  213.     eResult = mDepthGenerator.Create( mContext );   
  214.     CheckOpenNIError( eResult, "Create depth generator" );    
  215.   
  216.     // 4. create image generator   
  217.     xn::ImageGenerator mImageGenerator;  
  218.     eResult = mImageGenerator.Create( mContext );   
  219.     CheckOpenNIError( eResult, "Create image generator" );  
  220.   
  221.     // 5. set map mode    
  222.     XnMapOutputMode mapMode;   
  223.     mapMode.nXRes = 640;    
  224.     mapMode.nYRes = 480;   
  225.     mapMode.nFPS = 30;   
  226.     eResult = mDepthGenerator.SetMapOutputMode( mapMode );    
  227.     eResult = mImageGenerator.SetMapOutputMode( mapMode );    
  228.   
  229.     //由于 Kinect 的深度摄像机和彩色摄像机是在不同的位置,而且镜头本身的参数也不完全相同,所以两个摄像机所取得的画面会有些微的差异  
  230.     //将深度摄像机的视角调整到RGB摄像机位置  
  231.     // 6. correct view port    
  232.     mDepthGenerator.GetAlternativeViewPointCap().SetViewPoint( mImageGenerator );   
  233.   
  234.     // 7. start generate data    
  235.     eResult = mContext.StartGeneratingAll();    
  236.   
  237.     // 8. read data    
  238.     eResult = mContext.WaitNoneUpdateAll();    
  239.     while( (key!=27) && !(eResult = mContext.WaitNoneUpdateAll( ))  )   
  240.     {    
  241.         // 9a. get the depth map    
  242.         mDepthGenerator.GetMetaData(m_DepthMD);  
  243.         memcpy(m_depth16u.data,m_DepthMD.Data(), 640*480*2);  
  244.   
  245.         // 9b. get the image map    
  246.         mImageGenerator.GetMetaData(m_ImageMD);  
  247.         memcpy(m_rgb8u.data,m_ImageMD.Data(),640*480*3);  
  248.   
  249.         //将未知深度转为白色,便于在OPENCV中分析  
  250.         XnDepthPixel* pDepth = (XnDepthPixel*)m_depth16u.data;  
  251.   
  252.         for (XnUInt y = 0; y < m_DepthMD.YRes(); ++y)  
  253.         {  
  254.             for (XnUInt x = 0; x < m_DepthMD.XRes(); ++x, ++pDepth)  
  255.             {  
  256.                 if (*pDepth == 0)  
  257.                 {  
  258.                     *pDepth = 0xFFFF;  
  259.                 }  
  260.             }  
  261.         }  
  262.   
  263.   
  264.         //由于OpenNI获得的深度图片是16位无符号整数,而OpenCV显示的是8位的,所以要作转换。  
  265.   
  266.         //将距离转换为灰度值(0-2550mm 转换到 0-255),例如1000毫米转换为 1000×255/2550 = 100  
  267.         //m_depth16u.convertTo(m_DepthShow,CV_8U, 255/2096.0);  
  268.         m_depth16u.convertTo(m_DepthShow,CV_8U, 255/2550.0);  
  269.   
  270.         //可以考虑根据数据缩减图像大小到有效范围  
  271.   
  272.         //在此对灰度图像进行处理,平滑和去噪声  
  273.         //medianBlur(m_DepthShow, m_DepthThreshShow, 3);  
  274.         //m_DepthThreshShow.copyTo(m_DepthShow);  
  275.         //medianBlur(m_DepthThreshShow, m_DepthShow, 3);  
  276.         blur(m_DepthShow, m_DepthThreshShow, Size(3, 3));  
  277.         //m_DepthThreshShow.copyTo(m_DepthShow);  
  278.         blur(m_DepthThreshShow, m_DepthShow, Size(3, 3));  
  279.   
  280.         Mat  pyrTemp( 240,320,CV_8UC1);  
  281.         pyrDown(m_DepthShow, pyrTemp);  
  282.         pyrUp(pyrTemp, m_DepthShow);  
  283.   
  284.         //dilate(m_DepthShow, m_DepthThreshShow, Mat(), Point(-1,-1), 3);  
  285.         //erode(m_DepthThreshShow, m_DepthShow, Mat(), Point(-1,-1), 3);  
  286.   
  287.         //for(int i = 0; i < m_depth16u.rows; i++)  
  288.         //  for(int j = 0; j < m_depth16u.cols; j++)  
  289.         //  {  
  290.         //      if(m_depth16u.at<unsigned short>(i,j) < 1)  
  291.         //          m_depth16u.at<unsigned short>(i,j) == 0xFFFF;  
  292.   
  293.         //      //m_depth16u.at<double>(i,j)=1./(i+j+1);  
  294.         //  }  
  295.   
  296.         //RGB和BGR在内存对应的位置序列不同,所以也要转换。  
  297.         cvtColor(m_rgb8u,m_ImageShow,CV_RGB2BGR);  
  298.   
  299.         //imshow("depth", m_DepthShow);  
  300.         //imshow("image", m_ImageShow);  
  301.   
  302.         double  thd_max = 0xFFFF;  
  303.         double  thd_val = 100.0;  
  304.   
  305.         //反转黑白图像,以便找到最大外部轮廓  
  306.         //threshold(m_DepthShow, m_DepthThreshShow, thd_val, thd_max, CV_THRESH_BINARY);  
  307.         threshold(m_DepthShow, m_DepthThreshShow, thd_val, thd_max, CV_THRESH_BINARY_INV);  
  308.         imshow("depthThresh", m_DepthThreshShow);  
  309.   
  310.         findHand(m_DepthThreshShow, m_HandShow);  
  311.         imshow( "Hand", m_HandShow );  
  312.   
  313.         key=cvWaitKey(20);  
  314.     }  
  315.   
  316.     // 10. stop    
  317.     mContext.StopGeneratingAll();  
  318.     mContext.Shutdown();    
  319.   
  320.     return 0;  
  321. }  
  322.   
  323. int _tmain(int argc, _TCHAR* argv[])  
  324. {  
  325.     HandDetect();  
  326. }  

 


0 0
原创粉丝点击