一、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);
}
来源:https://www.cnblogs.com/farewell-farewell/p/6010816.html