深入理解OpenCV:实用计算机视觉项目解析(原书第3版)
上QQ阅读APP看书,第一时间看更新

1.2.4 用皮肤检测来生成外星人造型

前面已经生成了素描模式、卡通模式(绘画加素描掩码)和邪恶模式(绘画加邪恶掩码),为了好玩,让我们来尝试一些更复杂的东西:外星人模式。通过检测面部的皮肤区域,然后将皮肤颜色改变为绿色。

1.2.4.1 皮肤检测算法

有很多不同的检测皮肤区域的技术,从简单的使用RGB(Red-Green-Blue)或HSV(Hue-Saturation-Brightness)的颜色阈值法,或者颜色直方图计算和重投影,到基于混合模型的复杂机器学习算法等,这些复杂的算法需要在CIELab颜色空间对相机标定并且需要用人脸样本数据进行离线训练。但即便是复杂的算法,对不同的相机、光照条件和皮肤类型也不一定能稳健地工作。因为我们希望皮肤检测能够在嵌入式设备上运行,而不需要标定或训练,并且我们仅需要用皮肤检测来做一个有趣的图像滤波器,因此在这里使用简单的皮肤检测算法就足够了。然而,树莓派相机模块中的微型相机传感器对颜色的反应往往变化很大,我们希望在没有标定的情况下对任何肤色的人进行皮肤检测,所以需要比简单的颜色阈值更强大的东西。

例如,当色调较红、饱和度较高(但不是极高)、亮度不太黑或太亮时,一个简单的HSV皮肤检测器就会将这些区域的所有像素都当成皮肤。但是手机相机或者树莓派相机模块通常白平衡差,因此一个人的皮肤看上去要偏蓝而不是偏红,这也是使用简单HSV阈值法面临的主要问题。

更好的解决方案是使用Haar或LBP级联分类器来执行人脸检测(第5章会介绍),然后查看检测到的脸部中间像素的颜色范围,因为实际人物的皮肤像素事先知道,然后对有相似颜色的像素进行全图或邻域扫描,以确定人脸中心。这样做的好处是不管人的肤色如何,甚至他们的皮肤在图像中偏蓝或偏红,都有可能找到一些真实皮肤区域。

遗憾的是,使用级联分类器的人脸识别算法在目前的嵌入式设备上运行缓慢,因此这类算法不太适合实时嵌入式应用。另一方面,我们可以利用移动应用和一些嵌入式系统的(移动)优势,可假定用户能拿着相机从很近的距离直接对准一个人的脸,因此要求用户将人脸放在指定位置并与相机保持一定的距离是完全合理的,这样就不需要去检测位置和人脸大小。这也是很多手机应用会要求用户将脸放在正确位置或用手动拖动屏幕上的点来确定人脸在图像中的位置的基础。因此,让我们在屏幕中间简单地画一个人脸轮廓,并要求用户将他们的脸移动到所显示的位置和大小。

1.2.4.2 显示用户放置脸的位置

当外星人模式首次启动时,我们将在相机屏幕上画出脸部轮廓,让用户知道将脸放置在哪个位置。以固定的宽高比0.72来画一个大椭圆,它占整个图像高度的70%,这样根据相机的纵横比,脸部不会变得太瘦或太胖:

为了让它看上去更像是一张脸,让我们画出两只眼睛的轮廓。为了让所画的眼睛看上去更加真实(参见下图),不要直接用椭圆作为眼睛轮廓,而是用上椭圆作为眼睛的上半部分,下椭圆作为眼睛的下半部分。为此,我们可以通过对ellipse()函数指定开始和结束角度来实现:

可用这样的方法来画下嘴唇:

为了提示用户将脸放在指定位置,可在屏幕上显示一条提示信息!

现在可将已画好的人脸轮廓叠加到要显示的图像上,使用alpha混合来将卡通图像与该轮廓相结合。

最终得到人脸结果如下图,这里并没有检测人脸的位置,因为用户可将人脸放置在这个轮廓中: