Advertisement

学习OpenCV——hand tracking手势跟踪

阅读量:

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

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

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

背景差分:取前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);
    
 	}
    
 	else
    
 		accumulate(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);
    
 }
    
    
    
    

全部评论 (0)

还没有任何评论哟~