一、RGB color space
檢測代碼如下:
void SkinRGB(IplImage* src,IplImage* dst) { //RGB顏色空間 //均勻照明:R>95,G>40,B>20,R-B>15,R-G>15,R>B%R //側向照明:R>200,G>210,B>170,R-B<=15,R>B,G>B int height = src->height, width = src->width, channel = src->nChannels, step = src->widthStep; int b = 0, g = 1, r = 2; cvZero(dst); unsigned char* p_src = (unsigned char*)src->imageData; unsigned char* p_dst = (unsigned char*)dst->imageData; for(int j = 0; j < height; j++){ for(int i = 0; i < width; i++){ if((p_src[j*step+i*channel+r] > 95 && p_src[j*step+i*channel+g] > 40 && p_src[j*step+i*channel+b] > 20 && (p_src[j*step+i*channel+r] - p_src[j*step+i*channel+b]) > 15 && (p_src[j*step+i*channel+r] - p_src[j*step+i*channel+g]) > 15) || (p_src[j*step+i*channel+r] > 200 && p_src[j*step+i*channel+g] > 210 && p_src[j*step+i*channel+b] > 170 && (p_src[j*step+i*channel+r] - p_src[j*step+i*channel+b]) <= 15 && p_src[j*step+i*channel+r] > p_src[j*step+i*channel+b] && p_src[j*step+i*channel+g] > p_src[j*step+i*channel+b])) p_dst[j*width+i]=255; } } }
二、二次多項式模式檢測(RG color space)
void cvSkinRG(IplImage* rgb,IplImage* gray) { assert(rgb->nChannels==3&&gray->nChannels==1); const int R=2; const int G=1; const int B=0; double Aup=-1.8423; double Bup=1.5294; double Cup=0.0422; double Adown=-0.7279; double Bdown=0.6066; double Cdown=0.1766;
for (int h=0;h<rgb->height;h++) { unsigned char* pGray=(unsigned char*)gray->imageData+h*gray->widthStep; unsigned char* pRGB=(unsigned char* )rgb->imageData+h*rgb->widthStep; for (int w=0;w<rgb->width;w++){ int s=pRGB[R]+pRGB[G]+pRGB[B]; double r=(double)pRGB[R]/s; double g=(double)pRGB[G]/s; double Gup=Aup*r*r+Bup*r+Cup; double Gdown=Adown*r*r+Bdown*r+Cdown; double Wr=(r-0.33)*(r-0.33)+(g-0.33)*(g-0.33); if (g<Gup && g>Gdown && Wr>0.004){ *pGray=255; } else{ *pGray=0; } pGray++; pRGB+=3; } } }
三、Ycrcb之cr分量+otsu閾值化
原理: a.將RGB圖像轉換到YCrCb顏色空間,提取Cr分量圖像
b.對Cr做自適應二值化處理(Ostu法)
void cvSkinOtsu(IplImage* src, IplImage* dst) { //Cr自適應閾值法 // IplImage* img_ycrcb=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,3); IplImage* img_cr=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1); cvCvtColor(src,img_ycrcb,CV_BGR2YCrCb); cvSplit(img_ycrcb,0,img_cr,0,0); cvThresholdOtsu(img_cr,img_cr); cvCopy(img_cr,dst); cvReleaseImage(&img_ycrcb); cvReleaseImage(&img_cr); } void cvThresholdOtsu(IplImage* src, IplImage* dst) { int height=src->height,width=src->width,threshold=0; double histogram[256]={0}; double average=0.0,max_variance=0.0,w=0.0,u=0.0; IplImage* temp=cvCreateImage(cvGetSize(src),src->depth,1); if(src->nChannels!=1)cvCvtColor(src,temp,CV_BGR2GRAY); else cvCopy(src,temp); unsigned char* p_temp=(unsigned char*)temp->imageData; //計算灰度直方圖 // for(int j=0;j<height;j++) { for(int i=0;i<width;i++) { histogram[p_temp[j*width+i]]++; } } for(int i=0;i<256;i++)histogram[i]=histogram[i]/(double)(height*width); //計算平局值 for(int i=0;i<256;i++)average+=i*histogram[i]; for(int i=0;i<256;i++) { w+=histogram[i]; u+=i*histogram[i]; double t=average*w-u; double variance=t*t/(w*(1-w)); if(variance>max_variance) { max_variance=variance; threshold=i; } } cvThreshold(temp,dst,threshold,255,CV_THRESH_BINARY); cvReleaseImage(&temp); }
四、OpenCV自帶膚色檢測類——CvAdaptiveSkinDetector
通過顏色閾值分割膚色部分,皮膚檢測算法是在HSV空間進行。流程如下:
//構造函數 CvAdaptiveSkinDetector(int samplingDivider = 1, int morphingMethod = MORPHING_METHOD_NONE); /* 參數1:樣本采樣的間隔,默認情況下為1,即表示不進行降采樣 參數2:圖形學操作方式,即對用皮膚檢測后的圖像進行圖形學操作。其取值有3種可能——MORPHING_METHOD_ERODE(只進行一次腐蝕操作);MORPHING_METHOD_ERODE_ERODE(連續進行2次腐蝕操作);MORPHING_METHOD_ERODE_DILATE(先進行一次腐蝕操作,后進行一次膨脹操作) */
virtual void process(IplImage *inputBGRImage, IplImage *outputHueMask); /* 參數1:需要進行皮膚檢測的輸入圖像 參數2:輸出皮膚的掩膜圖像——值為1代表該像素為皮膚,值為0代表非皮膚。 */
PS:這個函數只有opencv的c版本的,因為CvAdaptiveSkinDetector這個類放在opencv源碼里的contrib目錄里,即表示比較新的但不成熟的算法。
#include <opencv\cv.h> #include <opencv\highgui.h> #include <contrib\contrib.hpp> #include <core\core.hpp> #include <imgproc\imgproc.hpp> #include<time.h> int main() {
CvCapture* capture=cvCreateCameraCapture(0); cvNamedWindow("Input Video",1); cvNamedWindow("Output Video",1); IplImage* img_src=NULL; IplImage* input_img=NULL; IplImage* output_mask=NULL; IplImage* output_img=NULL; clock_t start,finish; double duration; CvAdaptiveSkinDetector skin_detector(1,CvAdaptiveSkinDetector::MORPHING_METHOD_ERODE_DILATE); //定義膚色檢測算子 while(1)
{ img_src=cvQueryFrame(capture); if(!img_src) break; cvShowImage("Input Video",img_src); if(input_img==NULL){ input_img=cvCreateImage(cvGetSize(img_src),img_src->depth,img_src->nChannels); } cvCopy(img_src,input_img); output_img=cvCreateImage(cvGetSize(img_src),img_src->depth,img_src->nChannels); cvZero(output_img); if(output_mask==NULL){ output_mask=cvCreateImage(cvGetSize(img_src),img_src->depth,1); } //膚色檢測 // start=clock(); skin_detector.process(input_img,output_mask); finish=clock(); duration=(double)(finish-start)/CLOCKS_PER_SEC; printf("elapsed time :%.0f 毫秒\n",duration*1000); cvCopy(img_src,output_img,output_mask); cvShowImage("Output Video",output_img); char c=cvWaitKey(33); if(c==27)break; } cvReleaseCapture(&capture); cvDestroyWindow("Video"); }
五、HSV檢測
void cvSkinHSV(IplImage* src,IplImage* dst) { IplImage* hsv=cvCreateImage(cvGetSize(src),8,3); //IplImage* cr=cvCreateImage(cvGetSize(src),8,1); //IplImage* cb=cvCreateImage(cvGetSize(src),8,1); cvCvtColor(src,hsv,CV_BGR2HSV); //cvSplit(ycrcb,0,cr,cb,0); static const int V=2; static const int S=1; static const int H=0; //IplImage* dst=cvCreateImage(cvGetSize(_dst),8,3); cvZero(dst); for (int h=0;h<src->height;h++) { unsigned char* phsv=(unsigned char*)hsv->imageData+h*hsv->widthStep; unsigned char* psrc=(unsigned char*)src->imageData+h*src->widthStep; unsigned char* pdst=(unsigned char*)dst->imageData+h*dst->widthStep; for (int w=0;w<src->width;w++) { if (phsv[H]>=7&&phsv[H]<=29) { memcpy(pdst,psrc,3); } phsv+=3; psrc+=3; pdst+=3; } } //cvCopyImage(dst,_dst); //cvReleaseImage(&dst); }