1、膚色偵測法
膚色提取是基於人機互動方面常見的方法。因為膚色是人體的一大特征,它可以迅速從復雜的背景下分離出自己的特征區域。一下介紹兩種常見的膚色提取:
(1)HSV空間的膚色提取
HSV色彩空間是一個圓錐形的模型,具體如右圖所示:
色相(H)是色彩的基本屬性,就是平常說的顏色名稱,例如紅色、黃色等,
依照右圖的標准色輪上的位置,取360度得數值。(也有0~100%的方法確定) 飽和度(S)是色彩的純度,越高色彩越純,低則變灰。取值為0~100%。明度(V)也叫亮度,取值0~100。
根據膚色在HSV三個分量上的值,就可以簡單的偵測出一張圖像上膚色的部分。一下是膚色偵測函數的源代碼:
1 void skinDetectionHSV(IplImage* pImage,int lower,int upper,IplImage* process) 2 { 3 IplImage* pImageHSV = NULL; 4 IplImage* pImageH = NULL; 5 IplImage* pImageS = NULL; 6 IplImage* pImageProcessed = NULL; 7 IplImage* tmpH = NULL; 8 IplImage* tmpS = NULL; 9 static IplImage* pyrImage = NULL; 10
11 CvSize imgSize; 12 imgSize.height = pImage->height; 13 imgSize.width = pImage->width ; 14
15 //create you want to use image and give them memory allocation
16 pImageHSV = cvCreateImage(imgSize,IPL_DEPTH_8U,3); 17 pImageH = cvCreateImage(imgSize,IPL_DEPTH_8U,1); 18 pImageS = cvCreateImage(imgSize,IPL_DEPTH_8U,1); 19 tmpS = cvCreateImage(imgSize,IPL_DEPTH_8U,1); 20 tmpH = cvCreateImage(imgSize,IPL_DEPTH_8U,1); 21 pImageProcessed = cvCreateImage(imgSize,IPL_DEPTH_8U,1); 22 pyrImage = cvCreateImage(cvSize(pImage->width/2,pImage->height/2),IPL_DEPTH_8U,1); 23
24 //convert RGB image to HSV image
25 cvCvtColor(pImage,pImageHSV,CV_BGR2HSV); 26
27 //Then split HSV to three single channel images
28 cvCvtPixToPlane(pImageHSV,pImageH,pImageS,NULL,NULL); 29 //The skin scalar range in H and S, Do they AND algorithm
30 cvInRangeS(pImageH,cvScalar(0.0,0.0,0,0),cvScalar(lower,0.0,0,0),tmpH); 31 cvInRangeS(pImageS,cvScalar(26,0.0,0,0),cvScalar(upper,0.0,0,0),tmpS); 32 cvAnd(tmpH,tmpS,pImageProcessed,0); 33 //
34 //cvPyrDown(pImageProcessed,pyrImage,CV_GAUSSIAN_5x5); 35 //cvPyrUp(pyrImage,pImageProcessed,CV_GAUSSIAN_5x5); 36 //Erode and dilate
37 cvErode(pImageProcessed,pImageProcessed,0,2); 38 cvDilate(pImageProcessed,pImageProcessed,0,1); 39
40 cvCopy(pImageProcessed,process,0); 41 //do clean
42 cvReleaseImage(&pyrImage); 43 cvReleaseImage(&pImageHSV); 44 cvReleaseImage(&pImageH); 45 cvReleaseImage(&pImageS); 46 cvReleaseImage(&pyrImage); 47 cvReleaseImage(&tmpH); 48 cvReleaseImage(&tmpS); 49 cvReleaseImage(&pImageProcessed); 50 }
(2)YCrCb空間的膚色提取
YCrCb也是一種顏色空間,也可以說是YUV的顏色空間。Y是亮度的分量,而膚色偵測是對亮度比較敏感的,由攝像頭拍攝的RGB圖像轉化為YCrCb空間的話可以去除亮度對膚色偵測的影響。下面給出基於YCrCb膚色偵測函數的源代碼:
1 void skinDetectionYCrCb(IplImage* imageRGB,int lower,int upper,IplImage* imgProcessed) 2 { 3
4 assert(imageRGB->nChannels==3); 5 IplImage* imageYCrCb = NULL; 6 IplImage* imageCb = NULL; 7 imageYCrCb = cvCreateImage(cvGetSize(imageRGB),8,3); 8 imageCb = cvCreateImage(cvGetSize(imageRGB),8,1); 9
10 cvCvtColor(imageRGB,imageYCrCb,CV_BGR2YCrCb); 11 cvSplit(imageYCrCb,0,0,imageCb,0);//Cb
12 for (int h=0;h<imageCb->height;h++) 13 { 14 for (int w=0;w<imageCb->width;w++) 15 { 16 unsigned char* p =(unsigned char*)(imageCb->imageData+h*imageCb->widthStep+w); 17 if (*p<=upper&&*p>=lower) 18 { 19 *p=255; 20 } 21 else
22 { 23 *p=0; 24 } 25 } 26 } 27 cvCopy(imageCb,imgProcessed,NULL); 28 }
2、基於混合高斯模型去除背景法
高斯模型去除背景法也是背景去除的一種常用的方法,經常會用到視頻圖像偵測中。這種方法對於動態的視頻圖像特征偵測比較適合,因為模型中是前景和背景分離開來的。分離前景和背景的基准是判斷像素點變化率,會把變化慢的學習為背景,變化快的視為前景。
1 // 2
3 #include "stdafx.h"
4 #include "cv.h"
5 #include "highgui.h"
6 #include "cxtypes.h"
7 #include "cvaux.h"
8 # include <iostream>
9
10 using namespace std; 11
12
13 int _tmain(int argc, _TCHAR* argv[]) 14 { 15 //IplImage* pFirstFrame = NULL;
16 IplImage* pFrame = NULL; 17 IplImage* pFrImg = NULL; 18 IplImage* pBkImg = NULL; 19 IplImage* FirstImg = NULL; 20 static IplImage* pyrImg =NULL; 21 CvCapture* pCapture = NULL; 22 int nFrmNum = 0; 23 int first = 0,next = 0; 24 int thresh = 0; 25
26 cvNamedWindow("video",0); 27 //cvNamedWindow("background",0);
28 cvNamedWindow("foreground",0); 29 cvResizeWindow("video",400,400); 30 cvResizeWindow("foreground",400,400); 31 //cvCreateTrackbar("thresh","foreground",&thresh,255,NULL); 32 //cvMoveWindow("background",360,0); 33 //cvMoveWindow("foregtound",0,0);
34
35 if(!(pCapture = cvCaptureFromCAM(1))) 36 { 37 printf("Could not initialize camera , please check it !"); 38 return -1; 39 } 40
41 CvGaussBGModel* bg_model = NULL; 42
43 while(pFrame = cvQueryFrame(pCapture)) 44 { 45 nFrmNum++; 46 if(nFrmNum == 1) 47 { 48 pBkImg = cvCreateImage(cvGetSize(pFrame),IPL_DEPTH_8U,3); 49 pFrImg = cvCreateImage(cvGetSize(pFrame),IPL_DEPTH_8U,1); 50 FirstImg = cvCreateImage(cvGetSize(pFrame),IPL_DEPTH_8U,1); 51 pyrImg = cvCreateImage(cvSize(pFrame->width/2,pFrame->height/2),IPL_DEPTH_8U,1); 52
53 CvGaussBGStatModelParams params; 54 params.win_size = 2000; //Learning rate = 1/win_size;
55 params.bg_threshold = 0.7; //Threshold sum of weights for background test
56 params.weight_init = 0.05; 57 params.variance_init = 30; 58 params.minArea = 15.f; 59 params.n_gauss = 5; //= K =Number of gaussian in mixture
60 params.std_threshold = 2.5; 61
62 //cvCopy(pFrame,pFirstFrame,0);
63
64 bg_model = (CvGaussBGModel*)cvCreateGaussianBGModel(pFrame,¶ms); 65 } 66 else
67 { 68 int regioncount = 0; 69 int totalNum = pFrImg->width *pFrImg->height ; 70
71 cvSmooth(pFrame,pFrame,CV_GAUSSIAN,3,0,0,0); 72
73 cvUpdateBGStatModel(pFrame,(CvBGStatModel*)bg_model,-0.00001); 74 cvCopy(bg_model->foreground ,pFrImg,0); 75 cvCopy(bg_model->background ,pBkImg,0); 76 //cvShowImage("background",pBkImg); 77
78 //cvSmooth(pFrImg,pFrImg,CV_GAUSSIAN,3,0,0,0); 79 //cvPyrDown(pFrImg,pyrImg,CV_GAUSSIAN_5x5); 80 //cvPyrUp(pyrImg,pFrImg,CV_GAUSSIAN_5x5); 81 //cvSmooth(pFrImg,pFrImg,CV_GAUSSIAN,3,0,0,0);
82 cvErode(pFrImg,pFrImg,0,1); 83 cvDilate(pFrImg,pFrImg,0,3); 84
85 //pBkImg->origin = 1; 86 //pFrImg->origin = 1;
87
88 cvShowImage("video",pFrame); 89 cvShowImage("foreground",pFrImg); 90 //cvReleaseBGStatModel((CvBGStatModel**)&bg_model); 91 //bg_model = (CvGaussBGModel*)cvCreateGaussianBGModel(pFrame,0);
92 /*
93 //catch target frame 94 if(nFrmNum>10 &&(double)cvSumImage(pFrImg)>0.3 * totalNum) 95 { 96
97 first = cvSumImage(FirstImg); 98 next = cvSumImage(pFrImg); 99 printf("Next number is :%d /n",next); 100 cvCopy(pFrImg,FirstImg,0); 101 } 102 cvShowImage("foreground",pFrImg); 103 cvCopy(pFrImg,FirstImg,0); 104 */
105 if(cvWaitKey(2)== 27) 106 { 107 break; 108 } 109 } 110 } 111 cvReleaseBGStatModel((CvBGStatModel**)&bg_model); 112 cvDestroyAllWindows(); 113 cvReleaseImage(&pFrImg); 114 cvReleaseImage(&FirstImg); 115 cvReleaseImage(&pFrame); 116 cvReleaseImage(&pBkImg); 117 cvReleaseCapture(&pCapture); 118
119 return 0; 120 }
3、背景相減背景去除方法
所謂的背景相減,是指把攝像頭捕捉的圖像第一幀作為背景,以后的每一幀都減去背景幀,這樣減去之后剩下的就是多出來的特征物體(要偵測的物體)的部分。但是相減的部分也會對特征物體的灰階值產生影響,一般是設定相關閾值要進行判斷。以下是代碼部分:
1 int _tmain(int argc, _TCHAR* argv[]) 2 { 3 int thresh_low = 30; 4
5 IplImage* pImgFrame = NULL; 6 IplImage* pImgProcessed = NULL; 7 IplImage* pImgBackground = NULL; 8 IplImage* pyrImage = NULL; 9
10 CvMat* pMatFrame = NULL; 11 CvMat* pMatProcessed = NULL; 12 CvMat* pMatBackground = NULL; 13
14 CvCapture* pCapture = NULL; 15
16 cvNamedWindow("video", 0); 17 cvNamedWindow("background",0); 18 cvNamedWindow("processed",0); 19 //Create trackbar
20 cvCreateTrackbar("Low","processed",&thresh_low,255,NULL); 21
22 cvResizeWindow("video",400,400); 23 cvResizeWindow("background",400,400); 24 cvResizeWindow("processed",400,400); 25
26 cvMoveWindow("video", 0, 0); 27 cvMoveWindow("background", 400, 0); 28 cvMoveWindow("processed", 800, 0); 29
30 if( !(pCapture = cvCaptureFromCAM(1))) 31 { 32 fprintf(stderr, "Can not open camera./n"); 33 return -2; 34 } 35
36 //first frame
37 pImgFrame = cvQueryFrame( pCapture ); 38 pImgBackground = cvCreateImage(cvSize(pImgFrame->width, pImgFrame->height), IPL_DEPTH_8U,1); 39 pImgProcessed = cvCreateImage(cvSize(pImgFrame->width, pImgFrame->height), IPL_DEPTH_8U,1); 40 pyrImage = cvCreateImage(cvSize(pImgFrame->width/2, pImgFrame->height/2), IPL_DEPTH_8U,1); 41
42 pMatBackground = cvCreateMat(pImgFrame->height, pImgFrame->width, CV_32FC1); 43 pMatProcessed = cvCreateMat(pImgFrame->height, pImgFrame->width, CV_32FC1); 44 pMatFrame = cvCreateMat(pImgFrame->height, pImgFrame->width, CV_32FC1); 45
46 cvSmooth(pImgFrame, pImgFrame, CV_GAUSSIAN, 3, 0, 0); 47 cvCvtColor(pImgFrame, pImgBackground, CV_BGR2GRAY); 48 cvCvtColor(pImgFrame, pImgProcessed, CV_BGR2GRAY); 49
50 cvConvert(pImgProcessed, pMatFrame); 51 cvConvert(pImgProcessed, pMatProcessed); 52 cvConvert(pImgProcessed, pMatBackground); 53 cvSmooth(pMatBackground, pMatBackground, CV_GAUSSIAN, 3, 0, 0); 54
55 while(pImgFrame = cvQueryFrame( pCapture )) 56 { 57 cvShowImage("video", pImgFrame); 58 cvSmooth(pImgFrame, pImgFrame, CV_GAUSSIAN, 3, 0, 0); 59
60 cvCvtColor(pImgFrame, pImgProcessed, CV_BGR2GRAY); 61 cvConvert(pImgProcessed, pMatFrame); 62
63 cvSmooth(pMatFrame, pMatFrame, CV_GAUSSIAN, 3, 0, 0); 64 cvAbsDiff(pMatFrame, pMatBackground, pMatProcessed); 65 //cvConvert(pMatProcessed,pImgProcessed); 66 //cvThresholdBidirection(pImgProcessed,thresh_low);
67 cvThreshold(pMatProcessed, pImgProcessed, 30, 255.0, CV_THRESH_BINARY); 68
69 cvPyrDown(pImgProcessed,pyrImage,CV_GAUSSIAN_5x5); 70 cvPyrUp(pyrImage,pImgProcessed,CV_GAUSSIAN_5x5); 71 //Erode and dilate
72 cvErode(pImgProcessed, pImgProcessed, 0, 1); 73 cvDilate(pImgProcessed, pImgProcessed, 0, 1); 74
75 //background update
76 cvRunningAvg(pMatFrame, pMatBackground, 0.0003, 0); 77 cvConvert(pMatBackground, pImgBackground); 78
79
80 cvShowImage("background", pImgBackground); 81 cvShowImage("processed", pImgProcessed); 82
83 //cvZero(pImgProcessed);
84 if( cvWaitKey(10) == 27 ) 85 { 86 break; 87 } 88 } 89
90 cvDestroyWindow("video"); 91 cvDestroyWindow("background"); 92 cvDestroyWindow("processed"); 93
94 cvReleaseImage(&pImgProcessed); 95 cvReleaseImage(&pImgBackground); 96
97 cvReleaseMat(&pMatFrame); 98 cvReleaseMat(&pMatProcessed); 99 cvReleaseMat(&pMatBackground); 100
101 cvReleaseCapture(&pCapture); 102
103 return 0; 104 }