现在的位置: 首页 > 综合 > 正文

学习OpenCV——hand tracking手势跟踪

2018年10月24日 ⁄ 综合 ⁄ 共 4676字 ⁄ 字号 评论关闭

Refer from http://blog.csdn.net/yangtrees/article/details/7566284

简单的手势跟踪的代码。

原理是:背景差分+肤色检测。

背景差分:取前30帧图像取平均值,计算前30帧之差的和,再求均值。在背景平均值上下浮动的阈值之外的被检测出来。

肤色检测:利用YCrCb空间。

两个结果相与操作。

这种方式的优点:1.有效解决了肤色检测结果中总是检测到人脸的情况;

                                2.解决背景差分检测结果杂乱的情况;

缺点:背景要求相对稳定,反差越大越好,鲁棒性差。

注意事项:差分法由于涉及到累加图像,编码时需注意保证归一化!!!NORMALIZE

 

  1. #include "stdafx.h"  
  2. #include <cv.h>  
  3. #include <highgui.h>  
  4. #include <iostream>  
  5.   
  6. using namespace cv;  
  7. using namespace std;  
  8.   
  9. void intial(Mat src);  
  10. void accbackgound(Mat src,Mat pre);  
  11. void backgound(int count);  
  12. void foregound(Mat src,Mat pre);  
  13. void skin(Mat src);  
  14.   
  15. Mat bg,Th,mask0;  
  16. Mat bglow0,bglow1,bglow2;  
  17. Mat bghigh0,bghigh1,bghigh2;  
  18. Mat mask;  
  19. int high=10,low=10;  
  20.   
  21. int main()  
  22. {  
  23.     int count=0;  
  24.     VideoCapture capture;  
  25.     capture.open(0);  
  26.     Mat fram,prefram,result,fg;  
  27.     int framNum=0;  
  28.   
  29.   
  30.     while(capture.isOpened())  
  31.     {  
  32.         capture>>fram;  
  33.   
  34.         fram.convertTo(fram,CV_32FC3);  
  35.         normalize(fram,fram,1,0,CV_MINMAX);  
  36.         imshow("src",fram);  
  37.   
  38.         if(framNum==0)  
  39.         {  
  40.             intial(fram);     
  41.         }  
  42.         else if(framNum<30)  
  43.         {  
  44.             ++count;  
  45.             accbackgound(fram,prefram);  
  46.         }  
  47.         else if(framNum==30)  
  48.             backgound(count);  
  49.         else  
  50.         {  
  51.             foregound(fram,prefram);  
  52.             skin(fram);  
  53.         }  
  54.         fram.copyTo(prefram);  
  55.         framNum++;  
  56.   
  57.         char key=(char)waitKey(2);  
  58.         switch(key)  
  59.         {  
  60.         case 27:  
  61.             return 0;  
  62.             break;  
  63.               
  64.         }  
  65.     }  
  66. }  
  67.   
  68. void intial(Mat src)  
  69. {  
  70.     src.copyTo(bg);  
  71. }  
  72.   
  73. void accbackgound(Mat src,Mat pre)  
  74. {  
  75.     Mat temp;  
  76.     accumulate(src,bg);  
  77.     absdiff(src,pre,temp);  
  78.       
  79.     if (Th.data==NULL)  
  80.     {  
  81.         temp.copyTo(Th);  
  82.     }  
  83.     else  
  84.         accumulate(temp,Th);  
  85. }  
  86.   
  87. void backgound(int count)  
  88. {  
  89.     bg=bg/count;  
  90.     Th=Th/count;  
  91.       
  92.     normalize(bg,bg,1,0,CV_MINMAX);  
  93.     imshow("backgound",bg);   
  94.   
  95.     Mat t[3];  
  96.     Mat b[3];  
  97.     split(Th,t);  
  98.     split(bg,b);  
  99.     bglow0=b[0]-t[0]*low;  
  100.     bglow1=b[1]-t[1]*low;  
  101.     bglow2=b[2]-t[2]*low;  
  102.     bghigh0=b[0]+t[0]*high;  
  103.     bghigh1=b[1]+t[1]*high;  
  104.     bghigh2=b[2]+t[2]*high;  
  105.     cout<<"Start Traclking"<<endl;  
  106. }  
  107.   
  108. void foregound(Mat src,Mat pre)  
  109. {  
  110.     Mat temp0,temp1,temp2;  
  111.     Mat framNow[3];  
  112.     Mat frampre[3];  
  113.     framNow[0].setTo(Scalar(0,0,0));  
  114.     framNow[1].setTo(Scalar(0,0,0));  
  115.     framNow[2].setTo(Scalar(0,0,0));  
  116.     temp0.setTo(Scalar(0,0,0));  
  117.     temp1.setTo(Scalar(0,0,0));  
  118.     temp2.setTo(Scalar(0,0,0));  
  119.     /* 
  120.     split(pre,frampre); 
  121.     accumulateWeighted(frampre[0],bglow0,0.1); 
  122.     accumulateWeighted(frampre[0],bghigh0,0.1); 
  123.     accumulateWeighted(frampre[1],bglow1,0.1); 
  124.     accumulateWeighted(frampre[1],bghigh1,0.1); 
  125.     accumulateWeighted(frampre[2],bglow2,0.1); 
  126.     accumulateWeighted(frampre[2],bglow2,0.1); 
  127.     */  
  128.     split(src,framNow);  
  129.     inRange(framNow[0],bglow0,bghigh0,temp0);  
  130.     inRange(framNow[1],bglow1,bghigh1,temp1);  
  131.     inRange(framNow[2],bglow2,bghigh2,temp2);  
  132.     bitwise_or(temp0,temp1,temp0);  
  133.     bitwise_or(temp0,temp2,temp0);  
  134.     bitwise_not(temp0,temp0);  
  135.   
  136.     imshow("Show",temp0);  
  137.     temp0.copyTo(mask0);  
  138. }  
  139.   
  140. void skin(Mat src)  
  141. {  
  142.     src.convertTo(src,CV_8UC3,255);  
  143.     Mat yuv,dst;  
  144.     cvtColor(src,yuv,CV_BGR2YCrCb);  
  145.     Mat dstTemp1(src.rows, src.cols, CV_8UC1);  
  146.     Mat dstTemp2(src.rows, src.cols, CV_8UC1);  
  147.     // 对YUV空间进行量化,得到2值图像,亮的部分为手的形状  
  148.     inRange(yuv, Scalar(0,133,0), Scalar(256,173,256), dstTemp1);  
  149.     inRange(yuv, Scalar(0,0,77), Scalar(256,256,127), dstTemp2);  
  150.     bitwise_and(dstTemp1, dstTemp2, mask);  
  151.     dst.setTo(Scalar::all(0));  
  152.       
  153.     bitwise_and(mask,mask0,mask);  
  154.     src.copyTo(dst,mask);  
  155.   
  156.     vector< vector<Point> > contours;   // 轮廓  
  157.     vector< vector<Point> > filterContours; // 筛选后的轮廓  
  158.     vector< Vec4i > hierarchy;    // 轮廓的结构信息  
  159.     vector< Point > hull; // 凸包络的点集  
  160.     contours.clear();  
  161.     hierarchy.clear();  
  162.     filterContours.clear();  
  163.   
  164.     // 得到手的轮廓  
  165.     findContours(mask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);  
  166.             // 去除伪轮廓  
  167.     for (size_t i = 0; i < contours.size(); i++)  
  168.     {  
  169.         //approxPolyDP(Mat(contours[i]), Mat(approxContours[i]), arcLength(Mat(contours[i]), true)*0.02, true);  
  170.         if (fabs(contourArea(Mat(contours[i]))) > 1000&&fabs(arcLength(Mat(contours[i]),true))<2000)  //判断手进入区域的阈值  
  171.         {  
  172.             filterContours.push_back(contours[i]);  
  173.         }  
  174.     }  
  175.     // 画轮廓  
  176.     drawContours(src, filterContours, -1, Scalar(0,0,255), 2); //8, hierarchy);  
  177.     imshow("traclking",src);  
  178. }  

抱歉!评论已关闭.