人脸检测与自动磨皮
1. 简介
这学期的计算机视觉课,我们组的课程项目为“照片自动美化”,其中我负责的模块为人脸检测与自动磨皮。
功能为:用户上传一张照片,自动检测并定位出照片中的人脸,将照片中所有的人脸进行“磨皮”处理,使照片得到自动美化。
完整代码见于GitHub。
2. 重要步骤
人脸检测
OpenCV样例库中自带的训练结果采用的是Viola-Jones框架,选择了一种类Haar矩形特征,采用Ada-Boost这种自适应上升的算法来选择用于分类的特征并进行分类,最后使用弱分类器级联的架构来实现快速运算。
人脸检测使用了OpenCV自带的训练结果,且在OpenCV自带的样例库程序facedetect.cpp
的基础上修改而成,故不再放上此部分代码。
计划夏季学期中参考Kaggle上的人脸五官检测项目,换成卷积神经网络重新训练人脸检测模型,到时再更新此部分代码。
磨皮算法
尝试了多种滤波器之后,选用了PS教程《简单探讨可牛影像软件中具有肤质保留功能的磨皮算法及其实现细节》中介绍的算法:
- 对原图层
image
进行双边滤波,结果存入temp1
图层中。 - 将
temp1
图层减去原图层image
,将结果存入temp2
图层中。 - 对
temp2
图层进行高斯滤波,结果存入temp3
图层中。 - 以原图层
image
为基色,以temp3
图层为混合色,将两个图层进行线性光混合得到图层temp4
。 - 考虑不透明度,修正上一步的结果,得到最终图像
dst
。
若用Opacity表示图层4的不透明度,则5个步骤的综合公式为:
dst = (image * (100 - Opacity) + (image + 2 * GaussianBlur (bilateralFilter (image) - image + 128) - 256) * Opacity) /100 ;
将该算法用OpenCV实现的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Mat dst; int value1 = 3, value2 = 1; //磨皮程度与细节程度的确定 int dx = value1 * 5; //双边滤波参数之一 double fc = value1*12.5; //双边滤波参数之一 int p = 50; //透明度 Mat temp1, temp2, temp3, temp4; //双边滤波 bilateralFilter(image, temp1, dx, fc, fc); temp2 = (temp1 - image + 128); //高斯模糊 GaussianBlur(temp2, temp3, Size(2 * value2 - 1, 2 * value2 - 1), 0, 0); temp4 = image + 2 * temp3 - 255; dst = (image*(100 - p) + temp4*p) / 100; dst.copyTo(image); |
细节上的难点处理
- 获取识别结果:OpenCV人脸识别样例中给出的识别结果为圆心和半径,将其转换成矩形区域便于定义兴趣区域进行滤波。
- 矫正定位结果:为了实现不同长短人脸的完全覆盖,将矩形长度扩大至原来的1.3倍。
- 鲁棒性检查:
- 若上一步矫正后矩形区域超过图片尺寸,则以图片尺寸为上下边界。
- 若出现人脸不完整识别失败的情况,则对整张图片进行磨皮操作。
- 确定磨皮程度和细节程度参数:经过反复试验,将磨皮程度
value1
:细节程度value2
确定为3:1,并以此确定双边滤波的两个参数dx
和fc
。
3. 结果截图
-
正常样例1
-
正常样例2
- 特殊样例1:人脸不完整导致无法检测出人脸
- 特殊样例2:图片中有多个人脸
4. 结果分析
- 使用了Viola-Jones检测框架,能够实现较高的检测精度,使检测率和误检率分别保持在较高和较低的水平。
- 磨皮算法效果较好,能够较好地掩盖人脸上的瑕疵,而且较大限度地保留细节、边缘与质感。
- 在对人脸进行定位时,由于不同的人脸长短不同,Viola-Jones检测框架定位得到的结果不是很准确,导致某张人脸不能完全包括,或另一张人脸包括范围太大。在处理时采取了尽量选择较大范围的原则,在计算人脸矩形的长度时统一将半径扩大至了1.3倍,这样定位出的人脸区域不是很精确。
- 下一步考虑使用基于HSV色彩空间的人脸分割方法,将人脸准确定位在一个非矩形的区域里,以得到更好的磨皮效果,避免“少磨”或“多磨”了部分区域。