动态手跟踪

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

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

肤色检测:利用YCrCb空间。

两个结果相与操作。

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

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

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




#include <iostream>  
#include "opencv2/highgui/highgui.hpp"
 #include <stdio.h>  
#include <opencv2/core/core.hpp>  
#include <opencv2\opencv.hpp> 
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);  

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



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值