OpenCV常见的几种背景消除的方法
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 }