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