目录
2.5 定义 visualize_facial_landmarks()
1 项目介绍
这个是人脸部的68个关键点
我们可以看到
- 0-16点是下巴
- 16-21点是右眼眉(这里是镜像图像,是图中人的右眼眉)
- 22-26点是左眼眉
- 27-35点是鼻子
- 36-41点是右眼
- 42-47点是左眼
- 48-67点是嘴
我们现在有这样一张人脸
我们提取出人脸的每个部分,之后画出图像的所有器官部分
- 嘴
- 右眼眉,由于图像是镜像的图,现在标注的眼是这个人的右眼
- 左眼眉
- 右眼
- 左眼
- 鼻子
- 下巴
- 整体区域
我们的思路是先检测出图像中人脸的位置,然后使用68关键点对每个器官进行定位
如果找的图片的脸上胡子比较重,它识别嘴部的精度会很差
我们也可以检测一张图中的多个人脸
- 需要是正面脸,不然要改代码
2 代码实现
2.1 导入库
我们这里用到了collections中的OrderedDict,这个功能是创建有序字典,collections是python自带的库,dlib中有检测人脸68点的功能,我们直接使用写好的函数
2.2 定义参数
shape_predictor是我们dlib做68人脸关键点检测的一个文件(相当于是一个模型),image是我们要预测的图像
2.3 定义点位
定义68点的位置,上面有介绍过对应68点的位置,这里使用到了OrderedDict,它是一个单独的类,我们在这里举个例子
a = {'a':1,'c':2,'b':3}
print(type(a))
from collections import OrderedDict
b = OrderedDict([('a',1),('c',2),('b',3)])
print(type(b))
#调用的方式与和普通字典调用方式相同
print(a['a'])
print(b['a'])
除了人脸68点位还有人脸五点位,这个只能检测眼镜和鼻子,它的点位是这样定义的
- 0-1是右眼
- 2-3是左眼
- 4 是鼻子
- 上面这个在代码中没用到
2.4 定义 shape_to_np()
传入的参数shape是一个检测好的人脸关键点对象,我们在这个函数中进行处理,进入函数后我们下面会用到shape.num_parts这个方法,我们提前打印出来看一下
这个值是68,之后我们使用np.zeros创建全0的numpy.ndarry,大小为(68,2),我们打印出来看一下
一共68行,我就截取了头和尾
之后我们遍历68次,然后使用shape.part()取出每个点的坐标,然后赋值给coords对应的位置
现在我们看一下更新后的coords
没截全部,一头一尾
2.5 定义 visualize_facial_landmarks()
这个函数是画多边形用的,我们先看传入的参数
- image 要画的图像
- shape 多边形的点
- colors 颜色,默认为None,在函数中会定义
- alpha 这个是叠加比例,可以理解为多边形的透明度
进入函数后,首先复制两张图像
之后设置颜色,一共七个区域,我们设置为不同的颜色,如果我们之前设置了颜色就按设置的来,设置也必须设置7个
之后遍历七个区域,然后提取字典中的起始点和终止点两个索引值
之后把这些值交给pts
我们七个区域中,唯一不是闭合图形的就是下巴jaw,如果判定是下巴区域,我们就用点给它连起来
当然我们想给它画成多边形也能画,这样它的区域就是整张脸
这里是画在overlay上,一会儿我们要对overlay与output进行图像叠加
其余都是闭合图形,我们首先使用convexHull()计算凸包,参数为多边形点集合,它大致是这个意思
我们原图像是一个手
计算凸包之后画出来
如果想详细了解的话可以看一下这个 OpenCV入门之寻找图像的凸包(convex hull) - 山阴少年 - 博客园
凸包计算完成后我们将他画在overlay上
全部画完之后我们将overlay与output进行图像融合,比例为overlay 0.75,alpha 0.25,将融合后的图像赋值给output,最后返回融合后的图像
2.6 创建人脸检测器
dlib中有多种人脸检测的工具,我们使用的是get_frontal_face_detector(),这个是专门检测人的正脸的
2.7 创建人脸68点预测器
2.8 图像预处理
现在我们得到了宽为500,宽高比相同的灰度图像
2.9 人脸检测
这里有两个参数
- gray 要检测的图像
- 1 放大倍数,如果输入0是不放大,输入1是放大一倍,输入2是放大两倍,放的越大可以越好的检测图像中的所有人脸,相应运行的速度也会越慢
我们可以看一下rects
他会返回rectangles这个对象,通过名称我们可以得知,这个对象中都是矩形,那么我们尝试遍历一下其中的内容
发现只有里面只有一个值,这个值是一个矩形的坐标,这个是我们图像中人脸的坐标
2.10 找到关键点
现在我们对着原始图像的rect部分检测68个关键点
我们看一下这个shape
发现返回了一个这个对象
之后我们把这个对象传给上面定义的shape_to_np()
这个函数让我们拿到了大小为(68,2)的numpy.ndarray,其中内容为68个关键点的坐标
2.11 遍历每一部分
FACIAL_LANDMARKS_68_IDXS是我们上面定义的有序字典,一共七个部分
遍历的时候赋值了三个变量,我用mouth举个例子,name='mouth',i=48,j=68
2.11.1 写字
进入循环后,首先我们复制一张原图像,然后在复制图像上把name变量写在图片上
2.11.2 画圆
我们获取从i到j的点坐标,然后以它们为圆心,画半径为3的圆,之后使用红色进行填充
2.11.3 提取ROI
之后将从i-j的点拟合成轮廓,赋值给(x,y,w,h),之后我们截取这个矩形的地方,然后把它的宽变为250,宽高比与轮廓矩形相同的图像
2.11.4 展示ROI与画好点的图
2.12 展示所有区域
遍历结束后,我们将原图像与shape(大小为68*2的关键点坐标)传给visualize_facial_landmarks()进行多边形绘制,之后展示出来