Android端肤色检测
当今流行各种美颜美肤,而美颜美肤的前提是检测出人的皮肤。有科学家提出基于RGB颜色空间模型实现肤色检测算法,本篇文章主要讨论在Android端如何实现肤色检测。 参考该篇博客引用的算法:https://blog.csdn.net/wj080211140/article/details/23384927 根以上算法公式,实现肤色检测,需要考虑均匀光照和侧面光照两种情况
·
当今流行各种美颜美肤,而美颜美肤的前提是检测出人的皮肤。有科学家提出基于RGB颜色空间模型实现肤色检测算法,本篇文章主要讨论在Android端如何实现肤色检测。
参考该篇博客引用的算法:https://blog.csdn.net/wj080211140/article/details/23384927
根以上算法公式,实现肤色检测,需要考虑均匀光照和侧面光照两种情况:
/**
* 肤色检测,基于RGB颜色模型
* 在均匀光照下应满足以下判别式:
* R>95 AND G>40 B>20 AND MAX(R,G,B)-MIN(R,G,B)>15 AND ABS(R-G)>15 AND R>G AND R>B
* 在侧光拍摄环境下:
* R>220 AND G>210 AND B>170 AND ABS(R-G)<=15 AND R>B AND G>B
* @param pixels pixels
* @param width width
* @param height height
* @return pixels
*/
private int[] detectSkin(int[] pixels, int width, int height){
for(int i=0; i<width; i++){
for(int j=0; j<height; j++){
int pixel = pixels[j*width + i];
int red = (pixel>>16) & 0xff;
int green = (pixel>>8) & 0xff;
int blue = pixel & 0xff;
//判断RGB分量是否符合肤色范围
if ((red>95 && green>40 && blue>20 && Math.abs(red-green)>15 &&
((max(red, green, blue) - min(red, green, blue))>15) &&
red > green && red > blue) ||
(red>220 && green>210 && blue>170 &&
Math.abs(red-green)<=15 && red>blue && green>blue)) {
//white=255
pixels[j*width + i] = 255;
}
}
}
return pixels;
}
算法中使用到的比较三者最大值、三者最小值方法:
/**
* 计算三者最大值
* @param x x
* @param y y
* @param z z
* @return 最大值
*/
private static int max(int x, int y, int z){
int max = x;
if(y > max){
max = y;
}
if(z > max){
max = z;
}
return max;
}
/**
* 计算最小值
* @param x x
* @param y y
* @param z z
* @return 最小值
*/
private static int min(int x, int y, int z){
int min = x;
if(y < min){
min = y;
}
if(z < min){
min = z;
}
return min;
}
最终是调用上述算法,进行肤色检测,并且使用白色标记检测出的皮肤:
/**
* 执行肤色检测,并使用特定颜色标记
* @param bitmap bitmap
*/
private void doDetect(Bitmap bitmap){
if(bitmap == null){
return;
}
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] pixels = new int[width*height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
pixels = detectSkin(pixels, width, height);
Bitmap dst = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
dst.setPixels(pixels, 0, width, 0,0, width, height);
mHandler.obtainMessage(CODE_SHOW, dst).sendToTarget();
}
private void init(){
img_skin = (ImageView) findViewById(R.id.img_skin);
final Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.yuan);
//开启线程,执行肤色检测
new Thread(new Runnable() {
@Override
public void run() {
doDetect(bitmap);
}
}).start();
}
肤色检测结果,通过Handler在主线程显示标记皮肤的图像:
//handler中显示肤色检测后的图像
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == CODE_SHOW){
Bitmap bitmap = (Bitmap)msg.obj;
img_skin.setImageBitmap(bitmap);
}
}
};
最后来看下肤色检测效果图,使用白色标记检测结果:
补充:如果照片背景有人体肤色相似颜色,会导致误识别。这时,我们可以结合人体检测或者人脸检测,来针对图片的特定区域进行肤色检测,也就是排除外部背景环境干扰。
如果大家有问题或者有更好的肤色检测算法,可以互相讨论,相互学习。
更多推荐
所有评论(0)