您的位置:首页 > 运维架构

学习OpenCV——hand tracking手势跟踪

2016-04-17 19:34 399 查看
这几日,岛上风云突变,我这个倒霉孩子终究木有躲过感冒的魔掌,中枪鸟~~~

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

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

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

肤色检测:利用YCrCb空间。

两个结果相与操作。

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

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

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

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

[cpp] view plain copy

print?

#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);

}



from: http://blog.csdn.net/yangtrees/article/details/7566284
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: