幀差發去除背景類膚色影響的膚色檢測法

平常進行膚色檢測時會經常碰到有背景有類膚色的影響,對膚色檢測的效果有很大的影響。本文通過相鄰幀圖像的幀差,再對得到的幀差圖進行閾值分割處理就會得到圖像中運動的部分,將圖像中運動的部分設置爲感興趣的域,在對運動的部分進行閾值分割算法,分割出運動區域的膚色區域,如手,臉等,這樣的話就能有效的將背景中的類膚色區域的影響減小。

#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

發佈了33 篇原創文章 · 獲贊 28 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章