自适应肤色识别

肤色识别是数字图像的一个重要课题,现在已经有很多方法解决这个问题,其中不乏很多好的方法,但几乎都有各自的缺陷,很难达到完美,毕竟能否识别成功,识别是否精确取决于很多因素。

我做的是基于YUV空间和YQI空间的自适应光照的肤色识别,其原理非常简单,可以参考如下资料:

http://wenku.baidu.com/link?url=m01RY0xYaraGnOmWVSSthhuGZq-yuC_JuvCq9JknxLRaTpLWV9X_KhrF2f4XmnkHHgY8HB0ADy-YKFcoijBxj3KyWU-9YnjqcYlEcYoJdlC

不过这个文档有个地方有问题,在计算UV的相位角时,它的定义是:

Angle=arctan(|V|/|U|)

这样似乎是不对的,但是我在网上查了各种资料,都没有结果,不过根据我自己的推理,计算方法应该如下:

1.V>0 && U>0  //第一象限

Angle=arctan(V/U)*180/Pi;

2.V>0 && U<0//第二象限

Angle=180-arctan(|V|/|U|)*180/Pi;

3.V<0 && U<0//第三象限

Angle=180+arctan(|V|/|U|)*180/Pi;

4.V<0 && U>0//第四象限

Angle=360-arctan(|V|/|U|)*180/Pi;

根据我学的数学知识应该是这样没有错,不过这毕竟只是我个人的推理,若有错误请大家指出!

还有一个问题就是他的限定范围,他认为Angle值应该在[105,150],I值应该在[20,80],但这样得出效果并不怎么理想,有很多漏判和错判,虽然这是不可避免的!但还是可以改进的,这里我的解决办法是利用OpenCV的人脸识别,识别出人脸后再缩放在特定的区域(眼睛下面与嘴的上面那部分),在计算这部分的Angle值与I值得平均值,然后在动态放大

,这样识别效果就会好很多了!

下面是该算法的核心部分

//SkinIdentify.h

typedef unsigned char byte;

class SkinIdentify
{
public:
	SkinIdentify(void);
	virtual ~SkinIdentify(void);
	void Run(byte *pSrcR,byte *pSrcG,byte *pSrcB,int Height,int Width,byte *pDstRGBData,byte *pDstRGBData1,byte *pDstRGBData2,int AngleMin,int AngleMax,int IMin,int IMax,float *pfAngle,float *pfI);
	void RunAgain(int Height,int Width,byte *pDstRGBData,byte *pDstRGBData1,byte *pDstRGBData2,int AngleMin,int AngleMax,int IMin,int IMax,float *pfAngle,float *pfI);
	void CalAvgAI(byte *pSrcR,byte *pSrcG,byte *pSrcB,int Height,int Width,float &AvgA,float &AvgI);
private:
	void GammaAdjust(byte *pGray,float * pGamma,int Height,int Width);
};

//SkinIdentify.cpp

#include "StdAfx.h"
#include "SkinIdentify.h"
#include <cmath>

#define Pi 3.1416

SkinIdentify::SkinIdentify(void)
{
}

SkinIdentify::~SkinIdentify(void)
{
}

void SkinIdentify::Run(byte *pSrcR,byte *pSrcG,byte *pSrcB,int Height,int Width,byte *pDstRGBData,byte *pDstRGBData1,byte *pDstRGBData2,int AngleMin,int AngleMax,int IMin,int IMax,float *pfAngle,float *pfI)
{
	//Gamma矫正
	float *pGammaR=new float[Height*Width];
	float *pGammaG=new float[Height*Width];
	float *pGammaB=new float[Height*Width];
	GammaAdjust(pSrcR,pGammaR,Height,Width);
	GammaAdjust(pSrcG,pGammaG,Height,Width);
	GammaAdjust(pSrcB,pGammaB,Height,Width);
	//YUV与YQI空间的结合判断
	float U,V,Angle,I;
	float *pR=pGammaR,*pG=pGammaG,*pB=pGammaB;
	float Imin=IMin*1.0,Imax=IMax*1.0;
	float Amin=AngleMin*1.0,Amax=AngleMax*1.0;
	for(int i=0;i<Height;i++)
	{
		for(int j=0;j<Width;j++)
		{
			U=(-0.147)*pGammaR[j]-0.289*pGammaG[j]+0.436*pGammaB[j];
			V=0.615*pGammaR[j]-0.515*pGammaG[j]-0.100*pGammaB[j];
			//计算相位角
			if (U==0)
				Angle=0;
			else
				Angle=atan(abs(V/U));
			if(V>0&&U<0)
				Angle=180-Angle*180/Pi;
			else if(V<0&&U<0)
				Angle=180+Angle*180/Pi;
			else if(V<0&&U>0)
				Angle=360-Angle*180/Pi;
			//计算I值
			I=0.596*pGammaR[j]-0.274*pGammaG[j]-0.322*pGammaB[j];
			pfAngle[j]=Angle;//将Angle值保存,方便改变参数时直接调用RunAgain函数
			pfI[j]=I;       //同上
			//YUV空间的效果
			if (Angle>=Amin && Angle <=Amax)
			{
				pDstRGBData[j]=1;
			}
			else
			{
				pDstRGBData[j]=0;
			}
			//YQI空间的效果
			if(I>=Imin&&I<=Imax)
			{
				pDstRGBData1[j]=1;
			}
			else
			{
				pDstRGBData1[j]=0;
			}
			//结合的效果
			if(Angle>=Amin && Angle <=Amax &&I>=Imin&&I<=Imax)
			{
				pDstRGBData2[j]=1;
			}
			else
			{
				pDstRGBData2[j]=0;
			}
		}
		pSrcR+=Width;
		pSrcG+=Width;
		pSrcB+=Width;
		pGammaR+=Width;
		pGammaG+=Width;
		pGammaB+=Width;
		pfAngle+=Width;
		pfI+=Width;
		pDstRGBData+=Width;
		pDstRGBData1+=Width;
		pDstRGBData2+=Width;
	}
		delete[] pR;
	//	pGammaR=NULL;
		delete[] pG;
		//pGammaG=NULL;
		delete [] pB;
	//	pGammaB=NULL;

}

void SkinIdentify::GammaAdjust(byte *pGray,float * pGamma,int Height,int Width)
{
	float a=0.5;
	float x0=80.0,x1=175.0,x,y,cosx,Gammax;
	for (int i=0;i<Height;i++)
	{
		for(int j=0;j<Width;j++)
		{
			x=(float)pGray[j];
			if(x>=0.0&&x<=x0)
			{
				y=Pi*x/(2.0*x0);
			}
			else if(x>x0&&x<=x1)
			{
				y=Pi/2.0;
			}
			else
			{
				y=Pi-(Pi*(255.0-x))/(2.0*(255-x1));
			}
			cosx=cos(y);
			Gammax=1.0+a*cosx;
			pGamma[i*Width+j]=255*pow(((x*1.0)/255),1.0/Gammax);
		}
		pGray+=Width;
	}

}
void SkinIdentify::RunAgain(int Height,int Width,byte *pDstRGBData,byte *pDstRGBData1,byte *pDstRGBData2,int AngleMin,int AngleMax,int IMin,int IMax,float *pfAngle,float *pfI)
{
	//要调用这个函数必须先调用Run函数得到图片的相位角值与I值才行
	//而计算方法与Run函数几乎一致
	float Angle,I;
	float Imin=IMin*1.0,Imax=IMax*1.0;
	float Amin=AngleMin*1.0,Amax=AngleMax*1.0;
	for(int i=0;i<Height;i++)
	{
		for(int j=0;j<Width;j++)
		{
			Angle=pfAngle[j];
			I=pfI[j];
			if (Angle>=Amin && Angle <=Amax)
			{
				pDstRGBData[j]=1;
			}
			else
			{
				pDstRGBData[j]=0;
			}
			if(I>=Imin&&I<=Imax)
			{
				pDstRGBData1[j]=1;
			}
			else
			{
				pDstRGBData1[j]=0;
			}
			if(Angle>=Amin && Angle <=Amax &&I>=Imin&&I<=Imax)
			{
				pDstRGBData2[j]=1;
			}
			else
			{
				pDstRGBData2[j]=0;
			}
		}
		pfAngle+=Width;
		pfI+=Width;
		pDstRGBData+=Width;
		pDstRGBData1+=Width;
		pDstRGBData2+=Width;
	}
}

void SkinIdentify::CalAvgAI(byte *pSrcR,byte *pSrcG,byte *pSrcB,int Height,int Width,float &AvgA,float &AvgI)
{
	//此函数用于对人脸识别锁定的区域计算其平均相位角值与I值
	//计算方法与Run函数几乎一致
    float *pGammaR=new float[Height*Width];
	float *pGammaG=new float[Height*Width];
	float *pGammaB=new float[Height*Width];
	GammaAdjust(pSrcR,pGammaR,Height,Width);
	GammaAdjust(pSrcG,pGammaG,Height,Width);
	GammaAdjust(pSrcB,pGammaB,Height,Width);
    float U,V,Angle,I;
	float *pR=pGammaR,*pG=pGammaG,*pB=pGammaB;
	for(int i=0;i<Height;i++)
	{
		for(int j=0;j<Width;j++)
		{
			U=(-0.147)*pGammaR[j]-0.289*pGammaG[j]+0.436*pGammaB[j];
			V=0.615*pGammaR[j]-0.515*pGammaG[j]-0.100*pGammaB[j];
			if (U==0)
				Angle=0;
			else
				Angle=atan(abs(V/U));
			if(V>0&&U<0)
				Angle=180-Angle*180/Pi;
			else if(V<0&&U<0)
				Angle=180+Angle*180/Pi;
			else if(V<0&&U>0)
				Angle=360-Angle*180/Pi;
			I=0.596*pGammaR[j]-0.274*pGammaG[j]-0.322*pGammaB[j];
			AvgI+=I;
			AvgA+=Angle;
			if(Angle<1)
				int a=1;
		}
		pGammaR+=Width;
		pGammaG+=Width;
		pGammaB+=Width;
	}
	AvgA/=(Height*Width);
	AvgI/=(Height*Width);
    delete[] pR;
	delete[] pG;
	delete [] pB;
}

而利用MFC实现的可视界面和OpenCV实现的人脸识别部分我就不附上来了,有兴趣可以和我联系!

下面是识别效果

//原图

//YUV空间效果

YQI空间的效果

//结合效果

其实这幅图效果并不好,不过也能看到YUV与YQI的各自缺陷,YUV无法识别棕黑色,YQI则无法识别偏红的颜色,而综合还是不错的!

时间: 2024-10-05 07:42:51

自适应肤色识别的相关文章

【JAVA】图像识别——HSV肤色提取 【转载】

OSCHINA上看到各种语言的抓妹子图的程序段,拿来跑一跑,都是爬虫的机制,而地址一般都是固定的,格式固定,才能抓到想要的图,这显示不够智能,于是把作者的代码改掉,变成了个下载图片的爬虫.然后问题就来了,大量的图片,不是我想要的,于是想到了图像识别,目前主要的分支有,找相似图,人脸识别,鉴黄等. OSCHINA上看到各种语言的抓妹子图的程序段,拿来跑一跑,都是爬虫的机制,而地址一般都是固定的,格式固定,才能抓到想要的图,这显示不够智能,于是把作者的代码改掉,变成了个下载图片的爬虫.然后问题就来了

图像处理之基础---肤色检测算法 - 基于不同颜色空间简单区域划分的皮肤检测算法

本文涉及的很多算法,在网络上也有不少同类型的文章,但是肯定的一点就是,很多都是不配代码的,或者所附带的代码都是象征性的,速度慢,不优雅,不具有实用价值,本文努力解决这些问题. 文中各算法出现的顺序并不代表算法的优越性,仅仅是作者随机排布的而已. 2.基于RGB颜色空间的简单阈值肤色识别 在human skin color clustering for face detection一文中提出如下简单的判别算式: R>95 And G>40 And B>20 And R>G And R

【JAVA】图像识别——HSV肤色提取

OSCHINA上看到各种语言的抓妹子图的程序段,拿来跑一跑,都是爬虫的机制,而地址一般都是固定的,格式固定,才能抓到想要的图,这显示不够智能,于是把作者的代码改掉,变成了个下载图片的爬虫.然后问题就来了,大量的图片,不是我想要的,就这想到了图像识别,目前主要的分支有,找相似图,人脸识别,鉴黄等. 今天要说说肤色提取,大概就暴露了,我要选什么分支了,不多说,不多说 >_<! 肤色提取 开始使用了CSDN上某大神写的一段JAVA代码(用于检测黄色图片),使用了YUV色彩空间.效果还是很不错的. /

图像处理URL

随笔分类 - 图像处理/图像增强等 图像增强: 图像复原: 图像重建: 图像分割: 图像特效: 图像匹配: 图像形态学处理: 图像几何处理: 图像正交变换: 人工智能: 跟踪: 图像处理之增强---图像模糊检测 摘要: 这种检测可以做宽动态的检测,也可应用稳像算法我们实现了拉普拉斯方差算法,该算法提供给我们一个浮点数来代表具体图像的"模糊度".该算法快速,简单且易于使用--用拉普拉斯算子与输入图像做卷积然后计算方差即可.如果方差低于预定义阈值,图像就被标记为"模糊"

Atitit图像处理的用途

1.1. 分类识别 (人脸检测,肤色识别,人类检测:1 1.2. 炫丽的动态按钮生成:色相旋转+自己的草书等图片合成,图片自动裁剪1 1.3. 集成调用自绘gui接口:识别控件,按钮位置识别,为自动化鼠标操作选好roi1 1.4. Ocr 手写ocr等.2 1.5. 图像压缩2 1.6. 垃圾图片检测(体积过小图片,分辨率过小图片,损害图片检测)2 1.7. 模糊图片检测,方便识别模糊图片,删除2 1.8. 重复图片检测2 1.9. 高复杂度的验证码图片生成2 1.10. 绘画创作  水彩油画滤

Atitit atiuse软件系列

1.1.  Atian inputmethod 输入法 方言与多语言多文字支持 (au)1 1.2. File searcher 文件搜索器,支持压缩文件与正则表达式搜索 以及自定义扩展(au)2 1.3. spider爬虫,数据采集,数据解析(au)2 1.4.  atipostter发帖机(pub cms platform au)2 1.5.  Garb file clearer垃圾文件识别与清理器 (au)2 1.6.  人脸识别,用来照片分类,以及区分集体照与个人照 (au)2 1.7.

对皮肤美白算法的一些研究。

皮肤美白是现在任何一款流行的美颜软件必备的功能之一,不过你如果在互联网上搜索关于美白算法,能直接拿到并使用的可能不多.一直觉得这个算法其实很简单的,并且实现的方式可以说是多种多样,本文分享自己研究过的三种实现方式.     第一:借用色彩平衡算法 色彩平衡是Photoshop中常用的一个功能,发现这个算法能实现美白的是从一个叫DigitalCameraEnhance的软件中偶然遇到的,这个软件的界面如下图: 其中的调节中间影调一栏会发现右侧目的图像美白程度不断增加,于是我想到PS中有中间调的功能

PR视屏剪切

一款常用的视频编辑软件,由Adobe公司推出.现在常用的有CS4.CS5.CS6.CC.CC 2014及CC 2015版本.是一款编辑画面质量比较好的软件,有较好的兼容性,且可以与Adobe公司推出的其他软件相互协作.目前这款软件广泛应用于广告制作和电视节目制作中. 其最新版本为Adobe Premiere Pro CC 2015. 软件名称 adobe premiere 开发商 Adobe公司 软件平台 WIN XP ,WIN 7 ,WIN 8, WIN 10, Mac OS X 软件版本 最

人脸识别系列之人脸检测--训练基于肤色特征的检测

前言: 基于特征的方法是利用人脸的先验知识导出的规则进行人脸检测. 一般来说,常用的特征包括人脸和人脸器官典型的边缘和形状特征(如人脸轮廓.虹膜轮廓.嘴唇轮廓等).纹理特征(纹理是在图上表现为灰度或颜色分布的某种规律性,这种规律性在不同类别的纹理中有其不同特点,人脸有其特定的纹理特征).颜色特征(人脸肤色特征,目前主要有RGB,HSV,YCbCr,YIQ,HIS等彩色空间模型被用来表示人脸的肤色,从而进行基于颜色信息的人脸检测方法的研究). 人脸检测的方法: 基于规则/知识方法 – 人脸模式的变