学习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
这几天只写了个简单的手势跟踪的代码。
原理是:背景差分+肤色检测。
背景差分:取前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
相关文章推荐
- 学习OpenCV——鼠标事件(画框)
- linux目录结构
- Linux性能测试命令系列(2)- pstree
- 学习OpenCV——OpenMP
- 学习OpenCV——粒子滤波(网上两篇文章总结)
- 学习OpenCV——配置CUDA环境
- 运维人员写项目方案及推进项目的基本流程思路
- 运维人员写项目方案及推进项目的基本流程思路
- Linux LVM硬盘管理及LVM扩容
- 10种Linux下磁盘快照方式恢复系统
- 学习OpenCV——BOW特征提取函数(特征点篇)
- Tomcat运行Java Web内存溢出总结
- 整合Apache与PHP教程
- linux find 几个特殊点
- Linux系统误操作之-文件权限介绍和恢复分享
- linux系统下的c编程——my first program
- Linux系统误操作之-文件权限介绍和恢复分享
- Linux内核分析第八周——进程的切换和系统的一般执行过程
- 初识nginx配置文件--nginx.conf
- php面试题之四——Linux部分(高级部分)