手势动态识别(基于opencv的简单实现)

http://blog.csdn.net/anqing715/article/details/17653709



手势动态识别(基于opencv的简单实现)


先看下效果图



只能在离摄像头20~40CM,亮度不高的环境下使用。(当然你也可以自己加个控制条来控制手部的识别)

没有颜色直方图,没用到粒子滤波,也没有隐可马尔夫模型。

这里有篇论文是介绍的http://wenku.baidu.com/link?url=-QahWDlBFwLA9fZntwlGpzAE7M0hFkhktjQapb0tRj34NFF6yGVC6NofqX1oesko6wX3XLInD0pgBzbNwZCqYaRZsPPM4fSidppsS5oXxS3

只是简单的根据手部轮廓出现时记录的位置和手消失之前纪录好的位置简单地判断手是向左还是向右。

下面是源码,判断和画出手的轮廓的代码是从yangxian的博客下载的。http://blog.csdn.net/yang_xian521/article/details/6927411


  1. /************************************************************************/  
  2. /*  
  3. Description:    手势检测 
  4.                 先滤波去噪 
  5.                 -->转换到HSV空间 
  6.                 -->根据皮肤在HSV空间的分布做出阈值判断,这里用到了inRange函数, 
  7.                 然后进行一下形态学的操作,去除噪声干扰,是手的边界更加清晰平滑 
  8.                 -->得到的2值图像后用findContours找出手的轮廓,去除伪轮廓后,再用convexHull函数得到凸包络 
  9. Author:         Yang Xian 
  10. Email:          yang_xian521@163.com 
  11. Version:        2011-11-2 
  12. History:         
  13. */  
  14.   
  15. #include "stdafx.h"  
  16. #include <iostream>   // for standard I/O  
  17. #include <string>   // for strings  
  18. #include <iomanip>  // for controlling float print precision  
  19. #include <sstream>  // string to number conversion  
  20. #include<windows.h>  
  21. #include "cv.h"    
  22. #include "highgui.h"    
  23. #include "cxcore.h"  
  24. #include <opencv2/imgproc/imgproc.hpp>  // Gaussian Blur  
  25. #include <opencv2/core/core.hpp>        // Basic OpenCV structures (cv::Mat, Scalar)  
  26. #include <opencv2/highgui/highgui.hpp>  // OpenCV window I/O  
  27.   
  28. using namespace cv;  
  29. using namespace std;  
  30.   
  31. void main(int argc, char *argv[])  
  32. {  
  33.     int delay = 1;  
  34.     char c;  
  35.     int frameNum = -1;          // Frame counter  
  36.     bool lastImgHasHand=false;  
  37.   
  38.     int previousX=0;  
  39.     int previousY=0;  
  40.      CvCapture* pCapture = NULL;//  
  41.      pCapture = cvCaptureFromCAM(-1);  
  42.   
  43.     //Size refS = Size( (int) captRefrnc.get(CV_CAP_PROP_FRAME_WIDTH),  
  44.     //  (int) captRefrnc.get(CV_CAP_PROP_FRAME_HEIGHT) );  
  45.   
  46.     bool bHandFlag = false;  
  47.   
  48.     const char* WIN_SRC = "Source";  
  49.     const char* WIN_RESULT = "Result";  
  50.   
  51.     // Windows  
  52.     namedWindow(WIN_SRC, CV_WINDOW_AUTOSIZE );  
  53.     namedWindow(WIN_RESULT, CV_WINDOW_AUTOSIZE);  
  54.   
  55.     Mat frame;  // 输入视频帧序列  
  56.     Mat frameHSV;   // hsv空间  
  57.     Mat mask(frame.rows, frame.cols, CV_8UC1);  // 2值掩膜  
  58.     Mat dst(frame); // 输出图像  
  59.   
  60. //  Mat frameSplit[4];  
  61.   
  62.     vector< vector<Point> > contours;   // 轮廓  
  63.     vector< vector<Point> > filterContours; // 筛选后的轮廓  
  64.     vector< Vec4i > hierarchy;    // 轮廓的结构信息  
  65.     vector< Point > hull; // 凸包络的点集  
  66.   
  67.     bool movement=false;   
  68.     int count=0;  
  69.       
  70.     int presentX=0;  
  71.     int presentY=0;  
  72.       
  73.     while(true//Show the image captured in the window and repeat  
  74.     {  
  75.         //captRefrnc >> frame;  
  76.         int minX=320;//屏幕的一半  
  77.     int maxX=240;  
  78.     int minY=320;  
  79.     int maxY=240;  
  80.   
  81.         frame = cvQueryFrame( pCapture );  
  82.         if( frame.empty() )  
  83.         {  
  84.             cout << " < < <  Game over!  > > > ";  
  85.             break;  
  86.         }  
  87.         imshow( WIN_SRC, frame);  
  88.   
  89.         // Begin  
  90.   
  91.         // 中值滤波,去除椒盐噪声  
  92.         medianBlur(frame, frame, 5);  
  93.         cvtColor( frame, frameHSV, CV_BGR2HSV );  
  94.   
  95.         Mat dstTemp1(frame.rows, frame.cols, CV_8UC1);  
  96.         Mat dstTemp2(frame.rows, frame.cols, CV_8UC1);  
  97.         // 对HSV空间进行量化,得到2值图像,亮的部分为手的形状  
  98.         inRange(frameHSV, Scalar(0,30,30), Scalar(40,170,256), dstTemp1);  
  99.         inRange(frameHSV, Scalar(156,30,30), Scalar(180,170,256), dstTemp2);  
  100.         bitwise_or(dstTemp1, dstTemp2, mask);  
  101.     //  inRange(frameHSV, Scalar(0,30,30), Scalar(180,170,256), dst);         
  102.   
  103.         // 形态学操作,去除噪声,并使手的边界更加清晰  
  104.         Mat element = getStructuringElement(MORPH_RECT, Size(3,3));  
  105.         erode(mask, mask, element);  
  106.         morphologyEx(mask, mask, MORPH_OPEN, element);  
  107.         dilate(mask, mask, element);  
  108.         morphologyEx(mask, mask, MORPH_CLOSE, element);  
  109.         frame.copyTo(dst, mask);  
  110.         contours.clear();  
  111.         hierarchy.clear();  
  112.         filterContours.clear();  
  113.         // 得到手的轮廓  
  114.         findContours(mask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);  
  115.         // 去除伪轮廓  
  116.           
  117.         for (size_t i = 0; i < contours.size(); i++)  
  118.         {             
  119.         //  approxPolyDP(Mat(contours[i]), Mat(approxContours[i]), arcLength(Mat(contours[i]), true)*0.02, true);  
  120.             if (fabs(contourArea(Mat(contours[i]))) > 30000) //判断手进入区域的阈值  
  121.             {  
  122.                 filterContours.push_back(contours[i]);  
  123.             }  
  124.         }  
  125.         // 画轮廓  
  126.         if(filterContours.size()>0)  
  127.         {  
  128.       
  129.             count++;  
  130.             lastImgHasHand=true;  
  131.             drawContours(dst, filterContours, -1, Scalar(255,0,255), 3/*, 8, hierarchy*/);  
  132.   
  133.             for (size_t j=0; j<filterContours.size(); j++)  
  134.             {  
  135.                 convexHull(Mat(filterContours[j]), hull, true);  
  136.                 int hullcount = (int)hull.size();  
  137.                 for (int i=0; i<hullcount-1; i++)  
  138.                 {  
  139.                     line(dst, hull[i+1], hull[i], Scalar(255,255,255), 2, CV_AA);//白色             
  140.                     printf("num%d:x=%d\ty=%d\t\n",i,hull[i].x,hull[i].y);  
  141.                     if(hull[i].x>maxX)  
  142.                         maxX=hull[i].x;  
  143.                     if(hull[i].x<minX)  
  144.                         minX=hull[i].x;  
  145.                     if(hull[i].y>maxY)  
  146.                         maxY=hull[i].y;  
  147.                     if(hull[i].y<minY)  
  148.                         minY=hull[i].y;  
  149.                     printf("miniX=%d\tminiY=%d\tmaxX=%d\tmaxY=%d\t\n",minX,minY,maxX,maxY);  
  150.   
  151.                 }  
  152.                   
  153.                 line(dst, hull[hullcount-1], hull[0], Scalar(0,255,0), 2, CV_AA);//绿色,最后一条  
  154.                   
  155.                 if(count==1)//第一个轮廓的中心位置存在全局变量中,到最后一个再跟它比。  
  156.                 {  
  157.                     previousX=(minX+maxX)/2;  
  158.                     printf("previousX=%d\n",previousX);  
  159.                     previousY=(minY+maxY)/2;  
  160.                     printf("previousY=%d\n",previousY);  
  161.                 }  
  162.                 else  
  163.                 {  
  164.                     presentX=(minX+maxY)/2;  
  165.                     presentY=(minY+maxY)/2;  
  166.                 }  
  167.             }  
  168.         }  
  169.         else  
  170.         {     
  171.             if(lastImgHasHand==true)  
  172.             {  
  173.                 if((previousX-presentX)<0)//中文的大括号和英文的大括号用肉眼看不出来,坑啊  
  174.                 {  
  175.                     printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<left\n");//镜像,没有flip过来,所以这里注意点。  
  176.                     keybd_event(VK_LEFT,(BYTE)0, 0 ,0);  
  177.                     keybd_event(VK_LEFT, (BYTE)0, KEYEVENTF_KEYUP,0);  
  178.                 }  
  179.                 if((previousX-presentX)>0)  
  180.                 {  
  181.                      printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>right\n");  
  182.                      keybd_event(VK_RIGHT,(BYTE)0, 0 ,0);  
  183.                      keybd_event(VK_RIGHT, (BYTE)0, KEYEVENTF_KEYUP,0);  
  184.                 }  
  185.                 if((previousY-presentY)<0)  
  186.                 {  
  187.                     printf("downVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");  
  188.                 }  
  189.                 if((previousY-presentY)>0)  
  190.                 {  
  191.                     printf("upAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa\n");  
  192.                 }  
  193.   
  194.                 count=0;  
  195.                 lastImgHasHand=false;  
  196.             }  
  197.         }  
  198.           
  199.         imshow(WIN_RESULT, dst);  
  200.         dst.release();  
  201.   
  202.           
  203.         printf("previousX=%d\tpresentX=%d\tpreviousY=%d\tpresentY=%d\n",previousX,presentX,previousY,presentY);  
  204.         printf("count=%d\n",count);  
  205.         // End  
  206.         c = cvWaitKey(1);  
  207.         if (c == 27)   
  208.             break;  
  209.     }  
  210. }  


比较手部位置的流程图如下



展开阅读全文

没有更多推荐了,返回首页