帧差发去除背景类肤色影响的肤色检测法

平常进行肤色检测时会经常碰到有背景有类肤色的影响,对肤色检测的效果有很大的影响。本文通过相邻帧图像的帧差,再对得到的帧差图进行阈值分割处理就会得到图像中运动的部分,将图像中运动的部分设置为感兴趣的域,在对运动的部分进行阈值分割算法,分割出运动区域的肤色区域,如手,脸等,这样的话就能有效的将背景中的类肤色区域的影响减小。

#include <windows.h>
#include <algorithm>
#include "cv.h"
#include "highgui.h"
#include "cxcore.h"
using namespace std;

int n = 1;
int vmin = 10;
int vmax = 20;
CvRect rect;
CvPoint point[2];
void Threshold(IplImage *src , int lower , int higher)
{
	assert(src->nChannels == 1);
	for(int h = 0;h<src->height;h++)
				for(int w=0;w<src->width ;w++)
				{
					if(*(src->imageData +h*src->widthStep+w) >lower&&*(src->imageData +h*src->widthStep+w) <higher)
						*(src->imageData +h*src->widthStep+w) = 255;
					else 
						*(src->imageData +h*src->widthStep+w) =0;

						
				}
}

void findthemovepart(IplImage *src)
{
	assert(src->nChannels == 1);
	for(int h=0;h<src->height;h++)
		for(int w=0;w<src->width;w++)
		{
          if(w<point[0].x||h<point[0].y)
			  *(src->imageData+h*src->widthStep+w) = 0;
		  if(w>point[1].x||h>point[1].y)
			  *(src->imageData+h*src->widthStep+w) = 0;

		}
}
void findContours(IplImage *src)
{
	int max = 0;
	CvSeq *cont = 0;
	CvMemStorage *stor = cvCreateMemStorage(0);
	//cvSetImageROI(src , cvRect(point[0].x , point[0].y , point[1].x-point[0].x , point[1].y-point[0].y));
	cvFindContours(src , stor , &cont , sizeof(CvContour) , CV_RETR_LIST , CV_CHAIN_APPROX_SIMPLE , cvPoint(0,0));
	for( ; cont != 0 ; cont = cont->h_next)
	{
        if(cvContourArea(cont , CV_WHOLE_SEQ) > max)
		{
			max = cvContourArea(cont , CV_WHOLE_SEQ);
			rect = ((CvContour *)cont)->rect;
		}
	}
	cvReleaseMemStorage(&stor);
}
int _tmain(int argc, _TCHAR* argv[])
{
	//vector<CvPoint> points[2];
	IplImage *pfrimg = 0;
	IplImage *img  = 0;
	IplImage *img_YCrCb = 0;
	IplImage *bkimg = 0;
	CvMat *bkmat;
	IplImage *frimg = 0;
	IplImage *frimg_copy = 0;
	CvMat *frmat;
	CvMat *pfrmat;
	CvCapture *capture = 0;
	capture = cvCaptureFromCAM(0);

	cvNamedWindow("test" , 1);
	cvCreateTrackbar("lower" ,"test" , &vmin , 255 , NULL);
	cvCreateTrackbar("higher" ,"test" , &vmax , 255 , NULL);
	cvNamedWindow("video" , 1);
	if(!capture)
	printf("capture from cam failed\n");
	for( ; ;)
	{
		//Sleep(100);
		img=cvQueryFrame(capture);
		if(!img)
			printf("query from capture failed\n");
		if(n == 1)
		{
			//points[0].push_back(point[0]);
	        //points[1].push_back(point[1]);
			bkimg = cvCreateImage(cvGetSize(img) , 8 , 1);
			img_YCrCb = cvCreateImage(cvGetSize(img) , 8 , 3);
			cvCvtColor(img , img_YCrCb , CV_RGB2YCrCb);
			cvSplit(img_YCrCb , 0 , 0  , bkimg , 0);
			//cvCvtColor(img , bkimg , CV_BGR2GRAY);
			frimg = cvCreateImage(cvGetSize(img) , 8 , 1);
			frimg_copy = cvCreateImage(cvGetSize(img) , 8 ,1);
			pfrimg = cvCreateImage(cvGetSize(img), 8 ,1);
			//cvCvtColor(img , bkimg , CV_BGR2GRAY);
			bkmat = cvCreateMat(img->height , img->width , CV_32FC1);
			frmat = cvCreateMat(img->height ,img->width  , CV_32FC1);
			pfrmat = cvCreateMat(img->height ,img->width  , CV_32FC1);
			cvConvert(bkimg , bkmat);
			n = 0;
		}
		else 
		{

			point[0] = cvPoint(img->width , img->height);
			point[1] = cvPoint(0, 0 );

			cvCvtColor(img , img_YCrCb , CV_BGR2YCrCb);
			cvSplit(img_YCrCb , 0 , 0 , frimg , 0);
		    cvConvert(frimg , frmat );
			//cvAbsDiff(frmat , bkmat , pfrmat);
			cvSub(frmat , bkmat , pfrmat);
			cvConvert(frimg , bkmat);
			cvConvert(pfrmat , pfrimg);
			for(int h = 0;h<img->height;h++)
				for(int w=0;w<img->width ;w++)
				{/******************************************************************
				 寻找到运动目标的区域
				 *********************************************************************/
					if(*(pfrimg->imageData +h*pfrimg->widthStep+w) >16)
					{
						*(pfrimg->imageData +h*pfrimg->widthStep+w) = 255;
						if(w<point[0].x)
							point[0].x = w;
						if(h<point[0].y)
							point[0].y = h;
						if(w>point[1].x)
							point[1].x = w;
						if(h>point[1].y)
							point[1].y = h;
					}
					else 
						*(pfrimg->imageData +h*pfrimg->widthStep+w) =0;
				}
			    findthemovepart(frimg);
				Threshold(frimg , vmin , vmax);
				cvErode(frimg , frimg , 0 , 2);
				cvDilate(frimg , frimg , 0 ,5);//形态学操作
				cvCopy(frimg , frimg_copy);
				findContours(frimg);
			    cvRectangle(img , cvPoint(rect.x , rect.y) , cvPoint(rect.x+rect.width,rect.y+rect.height ) , CV_RGB(0 , 128 , 0) , 2 , CV_AA , 0);
				//cvRectangle(img , point[0] , point[1] , CV_RGB(0 , 128 , 0) , 2 , CV_AA , 0);
		    /*     if(rect.width < rect.height )
	{
		if((2*rect.y+rect.height)/2 < img->height/2)
		{
		//	printf("the car run forward\n");
			keybd_event(65 , 0 , 2 , 0);
			keybd_event(83 , 0 , 2 , 0);
			keybd_event(68 , 0 , 2 , 0);
			keybd_event(87 , 0 , 0 , 0);
		}

		if((2*rect.y+rect.height)/2 > img->height/2)
		{
			//printf("the car run back\n");
			keybd_event(65 , 0 , 2 , 0);//键盘模拟控制
			keybd_event(68 , 0 , 2 , 0);
			keybd_event(87 , 0 , 2 , 0);
			keybd_event(83 , 0 , 0 , 0);
		}

		//keybd_event(
	}
	if(rect.width >rect.height )
	{
		if((2*rect.x+rect.width )/2 < img->width/2)
		{
		//	printf(" the car run left\n");
			keybd_event(68 , 0 , 2 , 0);
			keybd_event(83 , 0 , 2 , 0);
			keybd_event(87 , 0 , 2 , 0);
			keybd_event(65 , 0 , 0 , 0);
		}

		if((2*rect.x+rect.width )/2> img->width/2)
		{
			printf("the car run right\n");
            keybd_event(65 , 0 , 2 , 0);
			keybd_event(83 , 0 , 2 , 0);
			keybd_event(87 , 0 , 0 , 0);
			keybd_event(68 , 0 , 0 , 0);
		}	
		}*/
			cvShowImage("test" , frimg);
			cvShowImage("video" , img);
			}
	
			if(cvWaitKey(2) == 27)
			{
				cvReleaseImage(&img);
				cvReleaseImage(&bkimg);
				cvReleaseImage(&frimg);
				cvDestroyAllWindows();
			}
	}
	return 0;
}


检测结果:

这样的话就没有检测到背景脸的部分,去除了脸的肤色部分对手检测的影响

效果演示:http://v.youku.com/v_show/id_XMjkyMDQ1ODYw.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值