肤色检测
在人像美化中,肤色检测有助于防止磨掉头发、胡子等需要保持细节的部分,也可以使美白算法仅作用于皮肤,不对人像周边环境产生影响。
网上找了一下肤色检测模型,效果都太差,换了一种思维,找个训练集,自己做一个。
训练结果,正确率大概85%,运行起来,确实还是比网上找的公式好,勉强可用了。
模型
算法最终反映为 opengl 的一个片断着色器,直接看shader代码吧。
varying vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
const vec3 CbC = vec3(0.5,-0.4187,-0.0813);
const vec3 CrC = vec3(-0.1687,-0.3313,0.5);
void main()
{
vec3 color = texture2D(inputImageTexture, textureCoordinate).rgb;
float x0 = color.r;
float x1 = color.g;
float x2 = color.b;
float x3 = dot(CbC, color);
float x4 = dot(CrC, color);
float pos = 0.0;
pos = float(x4 <=-0.0615369 ? (x3 <=0.0678488 ? (x3 <=0.0352417 ? 0 : (x2 <=0.686631 ? 0 : 1)) : (x3 <=0.185183 ? 1 : 0)) : (x4 <=-0.029597 ? (x3 <=0.0434402 ? 0 : (x1 <=0.168271 ? 0 : 1)) : 0));
gl_FragColor = vec4(pos);
}
肤色检测结果
训练方法
准备数据集
找到这个网站:
http://blog.csdn.net/wangkr111/article/details/44514097
下载了一组肤色检测的数据,用python脚本将其转换为机器学习所需的矩阵数据。提取 r、g、b、y、cb、cr分量值。
训练
机器学习库
机器学习算法库是自己造的*,使用C++开发,特别重视Cache命中率,部分地方引入OpenCL加速,性能可以说是一流的。
使用的代码如下:
#include "learn/ALLearnFactory.h"
#include "core/ALExpanderFactory.h"
#include "core/ALILabeldMethod.h"
#include "core/ALLabeldMethodFactory.h"
#include "learn/ALDecisionTree.h"
#include "loader/ALStandardLoader.h"
#include "learn/ALLogicalRegress.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <math.h>
#include "learn/ALRegressor.h"
using namespace std;
int main()
{
ALSp<ALFloatDataChain> c = ALStandardLoader::load("../../Data/Face_Dataset/train.data");
ALSp<ALFloatMatrix> X;
ALSp<ALFloatMatrix> Y;
ALStandardLoader::divide(c.get(), X, Y, 0);
//ALSp<ALISuperviseLearner> learner = new ALLogicalRegress(10000, 1.0);
ALSp<ALISuperviseLearner> learner = new ALDecisionTree(10, 0.01, 3);//决策树深限制为3
//ALSp<ALISuperviseLearner> learner = new ALRegressor;
ALSp<ALIMatrixPredictor> detected = learner->vLearn(X.get(),Y.get());
ALSp<ALFloatMatrix> YP = ALFloatMatrix::create(Y->width(), Y->height());
detected->vPredict(X.get(), YP.get());
size_t po = 0;
size_t pp = 0;
size_t fo = 0;
size_t fp = 0;
/*验证正确率*/
for (size_t i=0; i<YP->height(); ++i)
{
auto y = *(Y->vGetAddr(0, i));
auto yp = *(YP->vGetAddr(0, i));
if (yp > 0.5 && y > 0.5)
{
pp++;
}
if (yp <=0.5 && y <=0.5)
{
fp++;
}
if (y > 0.5)
{
po++;
}
else
{
fo++;
}
}
printf("PP/PO: %ld/%ld, %f, FP/FO: %ld/%ld, %f\n", pp, po, (double)pp/(double)po, fp, fo, (double)fp/(double)fo);
ofstream of("model_logical");
/*打印模型*/
detected->vPrint(of);
return 0;
}
模型选择
一开始本来用的是逻辑回归,因为这个出来的预测公式很简单,shader上运行速度快,但它的效果实在不行。后面改用了决策树,限制树深,以免模型太大。
至于为什么不用SVM:SVM出来的模型在shader上根本没法运行啊。。。