学习OpenCV——hand tracking手势跟踪

来源:互联网 发布:山东邦和康欣淘宝网 编辑:程序博客网 时间:2024/06/08 14:15

这几日,岛上风云突变,我这个倒霉孩子终究木有躲过感冒的魔掌,中枪鸟~~~

这几天只写了个简单的手势跟踪的代码。

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

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

肤色检测:利用YCrCb空间。

两个结果相与操作。

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

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

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

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

 

#include "stdafx.h"#include <cv.h>#include <highgui.h>#include <iostream>using namespace cv;using namespace std;void intial(Mat src);void accbackgound(Mat src,Mat pre);void backgound(int count);void foregound(Mat src,Mat pre);void skin(Mat src);Mat bg,Th,mask0;Mat bglow0,bglow1,bglow2;Mat bghigh0,bghigh1,bghigh2;Mat mask;int high=10,low=10;int main(){int count=0;VideoCapture capture;capture.open(0);Mat fram,prefram,result,fg;int framNum=0;while(capture.isOpened()){capture>>fram;fram.convertTo(fram,CV_32FC3);normalize(fram,fram,1,0,CV_MINMAX);imshow("src",fram);if(framNum==0){intial(fram);}else if(framNum<30){++count;accbackgound(fram,prefram);}else if(framNum==30)backgound(count);else{foregound(fram,prefram);skin(fram);}fram.copyTo(prefram);framNum++;char key=(char)waitKey(2);switch(key){case 27:return 0;break;}}}void intial(Mat src){src.copyTo(bg);}void accbackgound(Mat src,Mat pre){Mat temp;accumulate(src,bg);absdiff(src,pre,temp);if (Th.data==NULL){temp.copyTo(Th);}elseaccumulate(temp,Th);}void backgound(int count){bg=bg/count;Th=Th/count;normalize(bg,bg,1,0,CV_MINMAX);imshow("backgound",bg);Mat t[3];Mat b[3];split(Th,t);split(bg,b);bglow0=b[0]-t[0]*low;bglow1=b[1]-t[1]*low;bglow2=b[2]-t[2]*low;bghigh0=b[0]+t[0]*high;bghigh1=b[1]+t[1]*high;bghigh2=b[2]+t[2]*high;cout<<"Start Traclking"<<endl;}void foregound(Mat src,Mat pre){Mat temp0,temp1,temp2;Mat framNow[3];Mat frampre[3];framNow[0].setTo(Scalar(0,0,0));framNow[1].setTo(Scalar(0,0,0));framNow[2].setTo(Scalar(0,0,0));temp0.setTo(Scalar(0,0,0));temp1.setTo(Scalar(0,0,0));temp2.setTo(Scalar(0,0,0));/*split(pre,frampre);accumulateWeighted(frampre[0],bglow0,0.1);accumulateWeighted(frampre[0],bghigh0,0.1);accumulateWeighted(frampre[1],bglow1,0.1);accumulateWeighted(frampre[1],bghigh1,0.1);accumulateWeighted(frampre[2],bglow2,0.1);accumulateWeighted(frampre[2],bglow2,0.1);*/split(src,framNow);inRange(framNow[0],bglow0,bghigh0,temp0);inRange(framNow[1],bglow1,bghigh1,temp1);inRange(framNow[2],bglow2,bghigh2,temp2);bitwise_or(temp0,temp1,temp0);bitwise_or(temp0,temp2,temp0);bitwise_not(temp0,temp0);imshow("Show",temp0);temp0.copyTo(mask0);}void skin(Mat src){src.convertTo(src,CV_8UC3,255);Mat yuv,dst;cvtColor(src,yuv,CV_BGR2YCrCb);Mat dstTemp1(src.rows, src.cols, CV_8UC1);Mat dstTemp2(src.rows, src.cols, CV_8UC1);// 对YUV空间进行量化,得到2值图像,亮的部分为手的形状inRange(yuv, Scalar(0,133,0), Scalar(256,173,256), dstTemp1);inRange(yuv, Scalar(0,0,77), Scalar(256,256,127), dstTemp2);bitwise_and(dstTemp1, dstTemp2, mask);dst.setTo(Scalar::all(0));bitwise_and(mask,mask0,mask);src.copyTo(dst,mask);vector< vector<Point> > contours;// 轮廓vector< vector<Point> > filterContours;// 筛选后的轮廓vector< Vec4i > hierarchy;// 轮廓的结构信息vector< Point > hull;// 凸包络的点集contours.clear();hierarchy.clear();filterContours.clear();// 得到手的轮廓findContours(mask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);// 去除伪轮廓for (size_t i = 0; i < contours.size(); i++){//approxPolyDP(Mat(contours[i]), Mat(approxContours[i]), arcLength(Mat(contours[i]), true)*0.02, true);if (fabs(contourArea(Mat(contours[i]))) > 1000&&fabs(arcLength(Mat(contours[i]),true))<2000)//判断手进入区域的阈值{filterContours.push_back(contours[i]);}}// 画轮廓drawContours(src, filterContours, -1, Scalar(0,0,255), 2); //8, hierarchy);imshow("traclking",src);}


原创粉丝点击