,,人脸检测实战终极之OpenCV+Python实现人脸对齐

,,人脸检测实战终极之OpenCV+Python实现人脸对齐

本文主要是演示如何使用OpenCV、Python和面部标记来对齐人脸。文中的示例代码对我们的工作或学习有帮助,感兴趣的朋友可以学习一下。

目录

前言实现面部矫形器的导入,对齐必要的包并显示面部结果。

前言

这篇博文的目的是演示如何使用OpenCV、Python和面部标记来对齐人脸。

给定一组面部标志(输入坐标),我们的目标是扭曲图像并将其转换到输出坐标空间。

在这个输出坐标空间中,整个数据集中的所有面应该:

在图像中央。

旋转使眼睛在水平线上(即旋转面部使眼睛在同一Y坐标上)。

缩放以使面的大小大致相同。

为此,我们将首先调用一个实现的Python类FaceAligner来使用仿射变换对齐面部。

注意:仿射变换用于旋转、缩放、平移等。我们可以将以上三个需求全部打包成一个cv2.warpAffine调用;诀窍是创建旋转矩阵m。

然后,我们将创建一个示例驱动Python脚本来接受输入图像、检测人脸并对齐它们。

最后,我们将回顾使用OpenCV过程的人脸对齐的结果。

实现面部矫正器

人脸对齐算法本身是基于《用实际的计算机视觉项目掌握OpenCV》(Baggio,2012)的第8章。如果你有C背景或者兴趣,我强烈推荐。这本书提供了GitHub上的开放访问代码示例。

创建一个新的FaceAligner.py来实现FaceAligner类。

#导入必要的包

从imutils.face_utils.helpers导入face _ LANDMARKS _ 68 _ IDXS

从imutils.face_utils.helpers导入face _ LANDMARKS _ 5 _ IDXS

从imutils.face_utils.helpers导入shape_to_np

将numpy作为np导入

导入cv2

类别面对齐器:

def __init__(self,predictor,desiredLeftEye=(0.35,0.35),

desiredFaceWidth=256,desiredFaceHeight=None):

#存储面部标志预测值,左期望输出

#眼睛位置和所需的输出面宽度高度

自我预测值=预测值

self . desired lefteye=desired lefteye

self . desired face width=desired face width

self . desired face height=desired face height

#如果所需的面高度为None,则将其设置为

#所需的面部宽度(正常行为)

如果self.desiredFaceHeight为None:

self . desired face height=self . desired face width

导入必要的包

定义构造函数来启动我们的FaceAligner类。

我们的构造函数有4个参数:

预测器:面部标志预测器的模型。

RequiredLeftEye:一个可选的(x,y)元组,显示默认值并指定所需的输出左眼位置。对于这个变量,您通常会看到一个在20-40%范围内的百分比。这些百分比控制对齐后人脸的可见性。所用的确切百分比将因应用而异。当使用20%时,你基本上会得到一个“放大”的人脸视图,而当使用更大的值时,人脸会显得更“缩小”。

RequiredFaceWidth:另一个可选参数,它以像素为单位定义我们想要的面部。我们将这个值默认为256像素。

RequiredFaceHeight:最后一个可选参数,它以像素为单位指定所需的面部高度值。

接下来,让我们决定我们是想要一个正方形的人脸图像还是一个长方形的。请检查requiredFaceHeight是否为None。如果是,我们将其设置为desiredFaceWidth,这意味着面是方形的。正方形图像是一个典型的例子。或者,我们可以为desiredFaceWidth和desiredFaceHeight指定不同的值,以获得感兴趣的矩形区域。

既然我们已经构建了FaceAligner对象,接下来我们将定义一个函数来对齐面。

这个函数有点长,为了更容易理解,我把它分成了5个代码块:

定义对齐(自身、图像、灰色、矩形):

#将地标(x,y)坐标转换为NumPy数组

shape=self.predictor(灰色,矩形)

shape=shape_to_np(形状)

#提取左眼和右眼(x,y)坐标

(lStart,lEnd)=face _ LANDMARKS _ IDXS[' left _ eye ']

(rStart,rEnd)=face _ LANDMARKS _ IDXS[' right _ eye ']

leftEyePts=shape[lStart:lEnd]

rightEyePts=shape[rStart:rEnd]

定义align函数,它接受三个参数:

图像:RGB输入图像。

灰色:灰度输入图像。

矩形:由dlib的猪脸检测器生成的包围盒矩形。

应用dlib的面部标记预测值,并将标记转换为NumPy格式的(x,y)坐标。

接下来,从helpers.py脚本中找到的face _ LANDMARK _ IDXS字典中读取左眼和右眼区域。这些二元组值存储在左/右眼开始和结束索引中。

选择左视点和右视点。

接下来,计算每只眼睛的中心与眼睛质心之间的角度。

这个角度是对齐图像的关键部分。

眼睛绿线之间的角度,如下图所示,是我们比较关心的。

接下来是角度计算:

#计算每只眼睛的质心

leftEyeCenter=leftEyePts.mean(轴=0)。astype('int ')

rightEyeCenter=rightEyePts.mean(轴=0)。astype('int ')

#计算眼睛质心之间的角度

dY=右眼中心[1] -左眼中心[1]

dX=右眼中心[0] -左眼中心[0]

角度=np .度(np.arctan2(dY,dX)) - 180

通过平均每只眼睛的所有点(x,y)来计算每只眼睛的质心,也称为质心。

给定眼睛的中心,我们可以计算(x,y)坐标的差值,并取反正切来获得眼睛之间的旋转角度。

这个角度将允许我们纠正旋转。

为了确定角度,我们首先计算Y方向的增量dY。这是通过在第38行找到右眼中心和左眼中心之间的差异来实现的。

类似地,我们计算dX,即第39行中X方向的增量。

接下来,我们计算脸部旋转的角度。我们用NumPy的arctan2函数,参数dY和dX,然后换算成度,同时减去180得到角度。

在下面的代码块中,我们计算所需的右眼坐标(作为左眼位置的函数),并计算新结果图像的比例。

#根据计算所需的右眼x坐标

#左眼所需的x坐标

desiredrightyex=1.0-self . desired lefteye[0]

#通过以下方式确定新生成图像的比例

#眼睛之间的距离在*电流*中的比率

#图像中两眼之间的距离之比

# *所需的*图像

dist=np.sqrt((dX ** 2) (dY ** 2))

desired dist=(desiredrightyex-self . desired lefteye[0])

desired dist *=self . desired face width

scale=desiredDist/dist

根据所需左眼x坐标计算所需右眼。从1.0中减去self.desiredLeftEye[0],因为所需的RightEyeX值应该与图像的右边缘等距,因为对应的左眼X坐标与其左边缘的距离相同。

然后,通过获得当前图像中两眼之间的距离与期望图像中两眼之间的距离的比值,可以确定人脸的比例。

首先,计算欧几里得距离比dist。

接下来,使用左眼和右眼的X值之差计算所需距离desiredDist。

通过乘以第52行所需的面宽来更新所需的距离。这基本上是根据所需宽度缩放的眼距离。

最后,通过将desireddist除以我们之前计算的dist来计算比率。

现在您已经有了旋转角度和比例,您需要在计算仿射变换之前采取一些步骤。这包括找到眼睛之间的中点,计算旋转矩阵并更新其平移分量:

#计算中心(x,y)-坐标(即中点)

#在输入图像中的两只眼睛之间

eyes center=(int((leftEyeCenter[0]rightEyeCenter[0])//2),

int((leftEyeCenter[1]rightEyeCenter[1])//2))

#获取旋转矩阵以旋转和缩放面部

M=cv2.getRotationMatrix2D(眼睛中心,角度,刻度)

#更新矩阵的翻译部分

tX=self.desiredFaceWidth * 0.5

tY=self . desired face height * self . desired lefteye[1]

M[0,2]=(tX - eyesCenter[0])

M[1,2]=(tY - eyesCenter[1])

计算眼心,即左右眼的中点。这将用于我们的旋转矩阵计算。本质上,这个中点位于鼻子的顶部,也就是我们旋转面部的点:

为了计算旋转矩阵M,我们使用cv2.getRotationMatrix2D来指定眼睛中心、角度和比例。这三个值之前都已经计算过了,所以请根据需要返回。

2.getRotationMatrix 2D的参数描述如下:

眼睛中心:眼睛之间的中点是我们将围绕面部旋转的点。

角度:我们旋转面部的角度,以确保我们的眼睛在同一水平线上。

缩放:我们将放大或缩小图像的百分比,以确保图像缩放到所需的大小。

现在,必须更新矩阵的平移分量,使得在仿射变换之后,面部仍然在图像中。

取所需面宽的一半,并将值存储为tX,即X方向的平移。

为了计算tY,Y方向上的平移,将所需的面部高度乘以所需的左眼Y值desiredLeftEye[1]。

使用tX和tY,通过从它们对应的眼中点值中减去每个值来更新矩阵的平移分量(行66和67)。

然后应用仿射变换来对齐面:

#应用仿射变换

(w,h)=(self.desiredFaceWidth,self.desiredFaceHeight)

output=cv2.warpAffine(image,M,(w,h),

flags=cv2。间_立方)

#返回对齐的面

返回输出

为了方便起见,将desiredFaceWidth和desiredFaceHeight分别存储在W和H中(第70行)。

然后调用cv2.warpAffine执行最后一步。该函数调用需要3个参数和1个可选参数:

图像:人脸图像。

m:平移、旋转和缩放矩阵。

(w,h):输出表面所需的宽度和高度。

Flags:用于变形的插值算法,在本例中为INTER_CUBIC。要了解其他可能的徽标和图像转换,请参考OpenCV文档。

最后,对齐面。

对齐人脸

开始写面部对齐脚本,并命名为现在让我们把这个对齐类工作与一个简单的驱动程序脚本。打开一个新文件,命名为align _ faces.py:

#导入必要的包

从imutils.face_utils导入FaceAligner

从imutils.face_utils导入rect_to_bb

导入argparse

导入imutils

导入dlib

导入cv2

#构造参数解析器并解析参数

ap=argparse。ArgumentParser()

ap.add_argument('-p ','- shape-predictor ',必需=True,

help='面部标志预测器路径')

ap.add_argument('-i ','- image ',必需=True,

help='输入图像的路径')

args=vars(ap.parse_args())

如果您的系统上没有安装imutils和/或dlib,请确保通过pip安装/升级它们:

pip安装-升级imutils

pip安装-升级dlib

Win10安装dlib参考:如何安装dlib gpu版本

#初始化dlib的人脸检测器(基于HOG ),然后创建

#面部标志预测器和面部对准器

detector=dlib . get _ frontier _ face _ detector()

predictor=dlib . shape _ predictor(args[' shape _ predictor '])

fa=FaceAligner(预测值,desiredFaceWidth=256)

使用dlib的get _ frontal _ face _ detector初始化我们的检测器对象。

使用- shape-predictor实例化我们的面部标志预测器,这是dlib预训练预测器的路径。

通过在第21行初始化一个对象fa,利用上一节刚刚构建的FaceAligner类。我们指定了256像素的宽度。

接下来,加载图像并准备人脸检测:

#加载输入图像,调整其大小,并将其转换为灰度

image=cv2.imread(args['image'])

image=imutils.resize(image,width=800)

gray=cv2.cvtColor(image,cv2。COLOR_BGR2GRAY)

#显示原始输入图像并检测灰度中的人脸

#图像

cv2.imshow('输入',图像)

rects=检测器(灰色,2)

加载由命令行参数- image指定的图像。调整图像大小,保持第25行的纵横比,使其宽度为800像素。然后图像被转换成灰度。

为了处理输入图像中的人脸检测,我们使用了dlib的人脸检测器。这个函数返回rects,这是我们的检测器找到的面周围的边界框列表。

在下一个块中,我们遍历矩形,对齐每个面,并显示原始和对齐的图像。

#循环面部检测

对于矩形中的矩形:

#提取*原始*人脸的ROI,然后对齐人脸

#使用面部标志

(x,y,w,h)=rect_to_bb(rect)

face orig=imutils . resize(image[y:y h,x:x w],width=256)

faceAligned=fa.align(image,gray,rect)

#显示输出图像

cv2.imshow('Original ',faceOrig)

cv2.imshow('Aligned ',faceAligned)

cv2.waitKey(0)

开始循环。

对于dlib预测的每个边界框rect,我们将其转换为(x,y,w,h)格式。

然后,将框架的大小调整为256像素的宽度,保持纵横比。将此原始但已调整大小的图像保存为faceOrig。

对齐图像,指定图像,灰度图像和矩形。

最后,原始的和相应的对准的面部图像显示在相应窗口的屏幕上。

在任一窗口处于焦点时,等待用户按键,然后显示下一个原始/校准图像对。

对所有检测到的人脸重复上述过程,然后脚本退出。

展示结果

输入命令:

python align _ faces . py-shape-predictor shape _ predictor _ 68 _ face _ landmarks . dat-影像11.jpg

这就是这篇关于OpenCV Python的文章,人脸检测的极致,实现人脸对齐。有关Python OpenCV人脸对齐的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望大家以后能多多支持我们!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: