【class13】人工智能初步(人脸识别(4))

fmc121104 2024-07-10 17:31:02 阅读 60

【class13】

通过前面两课的学习,我们的程序已经实现了根据指定图片进行人脸识别的过程,即在图中标记人脸区域。

通过人脸检测接口detect(),我们得到了【调用接口信息】与【检测结果】,让我们快速的回顾一下这些数据。

调用接口信息

在存储检测结果的 ret_data 字典中:

ret_data['error_msg'] 记录错误信息,当它为'SUCCESS' 时表示检测成功。

我们可以利用这一点来判断检测的结果是否为空。

人脸检测结果

ret_data['result'] 用字典记录了人脸检测的结果,其中:

ret_data['result']['face_num'] 中记录识别到的人脸数量;

ret_data['result']['face_list'] 中用列表存储每张人脸的信息;

包含多个人脸信息的结果

当识别到多张人脸时,ret_data['result']['face_list'] 列表里会存储多个字典,且每个字典都对应了一个人脸的基本信息。

我们可以通过

ret_data['result']['face_list'][0]

ret_data['result']['face_list'][1]

ret_data['result']['face_list'][2]

的顺序依次取出。

人脸属性信息

检测到的面孔【位置信息】与配置options参数时添加的【检测质量】、【年龄预测】信息,也会依次记录在ret_data['result']['face_list']这些字典中。

若想同时获取所有的面孔信息,我们可以利用for遍历ret_data['result']['face_list'] 中的列表。

我们将遍历得到的面部信息字典存储在face_msg变量中,这样就可以快速方便的提取面孔数据。

比如face_msg['location']可以获得面部位置。

                 

在今天的课程中,我们就利用location中存储的面部位置数据,在图形中用矩形标记出人脸位置。

我们把这个过程分为了两个部分:

                                                        

在生活中,我们使用Photoshop、美图秀秀等图片工具对图片进行修改。

在Python中,这样的操作需要借助强大的图片处理模块Pillow(PIL)

PIL

PIL(Python Image Library)是python中功能强大的第三方 图像处理库。它提供了创建、裁剪、转换等几乎所有的图片处理功能。

我会在今天学习到PIL最常用的模块:

1. Image模块:打开、创建图片对象

2. ImageDraw模块:修改图片对象内容

先让我们学习一下第一个模块Image,完成第一个任务——在程序中打开一张图片。

代码结构

利用PIL打开图片的过程与open函数类似。

第一步,导入PIL中的Image模块;

第二步,确认要打开的图片路径;

第三步,利用Image.open函数打开路径下的图片并创建备份;

分析代码:

导入模块

从PIL库中,导入Image模块。注意,Image 中的字母‘I’需要大写。

图片的路径

img_path 变量中用来存储图片所在的路径。

Image.open

Image模块提供一个专用的open函数,即Image.open().

只需要以图片文件的路径作为参数,就可以将该图片创建为一个图片对象存储在变量中。

为图片创建备份

为了保证图片不会因为意外修改造成损坏,利用img.copy()方法可以拷贝一个与原图相同的文件。

在之后的修改操作中,只处理img_cp变量中拷贝文件,而不修改原图。

图片属性

输出img_cp 可以看到一些图片的属性信息。

包括图片的色彩模式、尺寸大小等。

利用PIL的Image模块打开图片需要以下几个步骤:

1. 从PIL中导入模块Image;

2. 设定图片存储的路径;

3. 使用with语句结合Image.open打开图片

4. 利用copy()方法创建图片。

到这里,我们完成了打开图片并创建图片对象的过程。接下来尝试我们对这个图片对象进行修改,在该图的脸部位置绘制一个矩形。

在PIL库中的ImageDraw模块能够帮我们实现这一过程。

代码结构

修改图片的代码结构如图所示,需要下面的步骤:

第1步,使用ImageDraw模块创建可修改的画布;

第2步,提取人脸检测结果中的位置信息,并格式化为画布可用的形式;

第3步,利用rectangle方法,在指定的位置绘制矩形。

分析代码:

ImageDraw

从PIL中导入ImageDraw模块,它能为程序提供一些修改图片的方法。

创建画布

通过ImageDraw.Draw()函数为图片创建画布。

把打开的图像对象 img_cp 作为参数传递给 ImageDraw.Draw()函数,该函数会返回一个画布对象,方便程序对图片进行修改。

绘制矩形

存储画布的draw_img变量提供一些列平面图形的绘制方法。其中,通过draw_img.rectangle可以在画布的指定位置中绘制一个矩形。

用列表存储绘图位置的变量xy,是rectangle函数必须传递的参数。

            

像素中的坐标

为了确定某个像素在图片中的位置,需要使用像素坐标系。

在像素坐标系中,图片的左上角为坐标轴的原点,x轴指向图片的右方,y轴指向图片的下方。

示意图:

确定一个矩形位置的方法

在图像中,我们通过两个点的位置来确定一个矩形区域。即:

1. 矩形左上角点的坐标

2. 矩形右下角点的坐标

提取出人脸的位置信息

location变量中存储着detect接口检测到的脸部位置信息

它是一个字典,我们通过下面的键来获取数据:

1. 与左边界的距离 location['left']

2. 与上边界的距离 location['top']

3. 人脸的宽度 location['width']

4. 人脸的高度 location['height']

获得pos参数所需要的值

其中left与top对应的是矩形左上角的坐标x1与y1,对于右下角的坐标:

left 与 width 相加得到x2;

top 与 height 相加得到y2。

这样,我们就得到了xy参数所需的所有数据,即确定了一个矩形位置。

         

提取关键点坐标

从location变量中提取left、top、width、height的数值,生成矩形左上角与右下角点的坐标,分别存储在x1、y1、x2、y2变量中。

设置矩形的位置

将这些坐标数据存储在一个列表中,它将作为第一个参数传递给rectangle函数。

存储格式为[x1, y1, x2, y2]。

设定矩形的边框颜色

设定矩形的边框颜色为红色。

将表示颜色的单词以字符串的形式传递给rectangle的outline参数,可以设定矩形边框的颜色。

比如在这里,边框的颜色设定为红色。传递outline参数要以关键字参数形式,即 outline='red'。

设置边框粗细

设置边框粗细为2像素,作为rectangle的第三个参数width传递。

rectangle 的width参数用来控制矩形边框的粗细,单位为像素。该参数依旧以关键字参数的形式传递,即width= 2。

绘制矩形

所有参数准备完成后,使用draw_img画布的rectangle()方法来绘制矩形。需要注意,outline 与 width 参数都需要以关键字参数的形式传递。

存储修改后的图片

最后利用图像的img_cp.save()方法存储修改后的图片。将图片保存路径'/User/img/draw.png'作为参数传递给save。

口罩判断

通过位置信息与PIL模块的结合,我们标记出了图中所有的面孔。

那么通过【检测质量】数据,我们能实现那些功能呢?

下节预告

在下节课的学习中,我们将利用这些数据来判断画面中人物的口罩佩戴情况。

也就是项目的最后一步——口罩佩戴情况检测。

【class13】

在上节课的学习中,我们通过人脸检测接口detect得到了人脸【位置信息】,并结合PIL提供的 Image 与 ImageDraw这两个模块分别对图片进行了打开与修改。

完成了项目的第三部——在图中标记人脸区域。

在今天的课程中,我们将进入项目的最后一步口罩佩戴情况监测。

这个过程可以拆分为2个小步骤:

1. 五官遮挡信息检测

2. 使用PIL模块为图片添加文字

让我们先从第一步开始~

为什么需要五官检测

在佩戴口罩的过程中,人脸的鼻子、嘴等部位会被口罩遮挡。

利用这一特点,我们可以判断识别到的人脸是否佩戴了口罩。

获得数据的方法

在前面学到的内容中,遍历 面孔列表 时,除了location中存储的位置信息以外,我们还有 质量检测 与 年龄预测两类信息。

其中,质量信息(quality)中存储着识别到的面孔情况,包含光照强度、清晰度、五官是否被遮挡等信息。

        

接下来让我们尝试提取每个面孔的质量信息。利用这些信息判断识别到的人脸是否佩戴了口罩,并用不同的颜色把它们标注出来。

代码结构

首先,快速预览一下完整的代码结构。

第1部分,遍历面孔列表获取五官遮挡信息;

第2部分,设定不同情况下矩形的颜色;

第3部分,在人脸区域绘制指定颜色的矩形

# 判断检测是否成功

if ret_data['error_msg'] == 'SUCCESS':

    # 遍历面孔信息列表

    for face_msg in ret_data['result']['face_list']:

        # 获取位置信息

        location = face_msg['location']

        # 获取人脸区域的坐标

        x1 = location['left']

        y1 = location['top']

        x2 = x1 + location['width']

        y2 = y1 + location['height']

       

        # 获取五官遮挡情况

        quality = face_msg['quality']['occlusion']

       

        # 判断鼻子与嘴巴是否被遮挡

        if quality['nose'] > 0.05 and quality['mouth'] == 1:

            color = 'lightgreen'

        else:

            color = 'red'

           

        # 绘制矩形图案

        draw_img.rectangle([x1, y1, x2, y2], outline=color, width=2)

       

    # 存储绘制的结果

    img_cp.save('/User/img/draw.png')

else:

print('识别失败')

分析代码:

遍历面孔列表

遍历面孔列表获取识别到的每一张面孔信息face_msg。与上节课相同,我们需要利用for循环遍历面孔列表里的每一条信息。

获取面孔质量

在人脸识别检测结果中,face_msg['quality']用来存储检测到的面孔质量。

其中,对五官的遮挡检测存储在face_msg['quality']['occlusion'],数值范围为0~1

我们需要这部分数据来判断嘴与鼻子的遮挡情况。

获取遮挡信息

从face_msg['quality']['occlusion']中获取五官遮挡情况,并存储在变量quality中。

变量quality是一个字典,我们需要从中获取quality['nose']与quality ['mouth']的值。

判断口罩佩戴的条件

正确佩戴口罩时,人的嘴巴会被口罩完全覆盖、鼻子部分会被大部分覆盖。

针对这一特点,我们可以设定判断条件:

当识别到的面孔嘴部的遮挡程度等于100%并且鼻子的遮挡程度大于50%时,即佩戴了口罩。

             

设定颜色区分

为了将判断结果在图中展示,我们使用颜色对未佩戴口罩的人进行区分。

如图所示,对已佩戴口罩的人使用绿色矩形标记,未佩戴口罩的人使用红色矩形标记。

                 

判断遮挡情况

设定判断口罩是否佩戴的条件。

判断面孔是否佩戴口罩,需要同时满足下列条件:

条件1:鼻子的遮挡度大于0.5;

条件2:嘴巴的遮挡程度等与1。

即“if 条件1 and 条件2”。

佩戴口罩时

若判断结果为真,设定颜色为lightgreen(浅绿色),存储在color变量中。

该变量会作为绘制矩形的边框颜色(outline参数)。

未佩戴口罩时

否则(若判断结果为假),将color变量设置为红色。

标记人脸区域

根据判断结果确定颜色后,利用上节课学习的矩形绘制方法rectangle,在画布的人脸区域绘制矩形。

存储结果

最后将标记结束的图片保存在指定路径下。

总结下这个过程,根据面孔五官的遮挡信息,判断其是否佩戴口罩。分为下面的步骤:

1. 遍历面孔列表获取【质量信息】中关于五官遮挡的信息。

2. 利用if语句判断鼻子与嘴巴的遮挡程度,并根据不同的情况设置颜色。

3. 在人脸区域绘制指定颜色的矩形,并保存。

现在,我们完成了对口罩佩戴的检测,并使用了不同的颜色标记出图像中的面孔。

除了颜色以外,有没有更清晰的方式来区分佩戴口罩的面孔呢?

当然有!直接用文字标注出来就好了~

接下来,我们来开始今天的第二部分内容——使用PIL模块为图片添加文字。

除了上节课学到的绘制矩形方法,画布提供draw_img.text()方法用来在指定的位置添加文字。

不过为了正确显示中文,这个过程还需要额外的字体文件支持。

让我们来详细的学习下这个过程,尝试为图片的指定位置添加一段文字。

代码结构

首先,快速预览一下完整的代码结构。

第1部分,打开图片并为其创建画布;

第2部分,读取字体文件,并创建字体对象;

第3部分,在画布的指定位置添加文字。

分析代码:

绘制文字的方法

在画布中的指定位置绘制文字,需要使用draw_img.text()方法。

text需要传入位置、内容、颜色、字体等参数。

其中,字体参数font需要传递一个存储文字样式与大小的字体对象。

字体文件

字体指的是文字在程序中显示的样式,比如我们常用的宋体、黑体等。

在电脑中,字体以文件的形式存储,常见的格式有.ttf、.ttc、.fon等。

windows系统的所有字体可以在“C://windows/fonts”路径下查看。

字体对象

为图片添加文字时,需要提前设定文字的字体与大小。

PIL提供一个字体管理模块ImageFont,其中ImageFont. truetype() 函数用来创建一个字体对象,参数为:

1. 字体路径:字体文件的位置

2. 字号:绘制文字的大小

  

导入ImageFont

从PIL中导入ImageFont模块用来管理字体文件。

注意区分大小写~

创建字体对象

使用ImageFont.truetype函数创建字体对象。

第一个参数为字体路径“/User/img/yahei_consola.ttf”以字符串的形式传递。

第二个参数为字体显示的为50像素,该参数必须使用整数传递。

最后将生成的字体对象存储在font变量中。

导入字体文件后,就可以利用draw_img.text()方法为画布添加文字了。

接下来对它的参数进行依次说明。

文字位置

在坐标位置(0,0)绘制文字。

确定文字位置的方法:

如图设定该坐标时,我们只需要传递文字左上角要对齐的坐标位置(x,y)。

内容与颜色

text的第二、三参数分别为要显示的文字内容与文字颜色。

在这里,我们要显示的文字内容为“夜曲编程专用水印”,颜色为“red”红色。

字体

text的最后一个参数font用来传递已经创建好的字体对象。

我们把font变量传递给text,这样文字将会以“雅黑体”、50像素的大小绘制。

存储绘制结果

所有的参数都准备好后,draw_img.text()就会将指定的文字内容绘制在画布中。

最后将修改后的图片img_cp存储在路径'/User/img/draw.png'下。

总结下为图片添加文字的步骤:

1. 从PIL中导入ImageFont模块,用来提供字体支持。

2. 使用ImageFont.truetype()函数创建字体对象,参数为字体文件路径与字号。

3. 使用draw_img.text()方法为画布添加文字,参数为文字位置、内容、颜色与字体。

'''修改图片标记出人脸'''

# 导入图片修改模块

from PIL import ImageDraw

# 创建画布

draw_img = ImageDraw.Draw(img_cp)

# 从PIL中导入ImageFont模块

from PIL import ImageFont

# 创建字体对象,

# 文件路径为'img/yahei_consola.ttf', 字号为50

font = ImageFont.truetype('img/yahei_consola.ttf', 50)

# 绘制文字: 左上角位置、内容、颜色、字体

draw_img.text([0, 0], '夜曲编程专用水印', 'red', font)

# 存储绘制的结果

img_cp.save('/User/img/draw.png')

接下来我们将文字添加到每张面孔的下方,实现这过程需要两步:

1. 设置自动变化的字体大小

为了避免添加的文字过大或者过小,我们需要根据面孔的大小来适应文字的大小;

2. 为文字绘制背景

为了让文字清晰可见,需要在文字的位置下绘制矩形背景,突出文字内容。

代码结构(上)

先来快速预览下【自适应文字】部分的代码结构。

第一部分,遍历面孔列表获取位置数据。

第二部分,根据面孔区域的高度来设置文字大小。

自适应字体大小

在识别的过程中,不同的照片、不同人检测到的人脸区域大小也不相同。

为了让文字的大小适应面孔标记的大小,我们设定文字大小为区域高度的五分之一。

前面我们说过,文字的大小只能使用整数类型。所以需要使用整除来确保计算结果不是浮点数(小数)。

自适应文字大小

除了字体文件路径以外,设定文字的大小为面孔标记的五分之一即:

文字大小 = 面孔高度 整除 5,

并传递给ImageFont.trutype()函数用来创建字体对象。

代码结构(下)

接下来快速预览下【绘制背景与文字】部分的代码结构。

第一部分,根据判断结果设定要添加的文字内容。

第二部分,找到文字与背景的位置修改图片。

确定文字内容

根据佩戴情况将不同的文字内容存储在text变量中。

当判断面孔符合佩戴口罩的条件时,text变量为“已佩戴口罩”;

当判断面孔不符合佩戴口罩的条件时,text变量为“未佩戴口罩”;

文字位置

为了将文字放置在识别标记的正下方,我们需要获取红色标记点的坐标。

如图所示,该坐标的值为(x1, y2)。

     

文字背景

在文字的位置绘制一个矩形充当背景。

绘制矩形的方法rectangle需要两个坐标来确定位置,如图所示:

左上角

坐标与文字坐标相同,即(x1, y2);

右下角

坐标为(x2, y2+背景区域想要的高度)。

绘制文字背景

绘制一个矩形作为文字的背景。

矩形位置为[x1, y2, x2, y2 + font_size*2],其中 font_size*2的目的是设定背景的高度等于字体大小的二倍。将color变量中的颜色传递给fill参数中。

fill参数是rectangle的一个可选参数,用来为矩形填充颜色。

绘制文字

在人脸区域的下方绘制文字。

使用text变量中的字符串作为文字内容,白色(white)作为文字的颜色。

绘制结束后保存图片。

    

总结下这个过程:

1. 创建字体对象,设定文字大小为面孔高度的五分之一;

2. 设定不同情况下(是否佩戴口罩)要显示的文字内容;

3. 绘制一个矩形作为文字背景;

4. 绘制文字,并保存图片。

当然啦,我们能做到的远不止这些。

通过为options['face_field']添加更多的配置项,可以对人脸进行进一步检测。

比如我们同时检测人脸的质量、年龄、性别数据,并用同样的的方式标记到图片中。

大家可以试一试

总结项目步骤:

恭喜你!

到这里我们就完成了人脸识别项目的所有步骤,帮助小叶实现了【通过人脸识别进行口罩检测】的程序~

利用人脸识别接口,我们还可以做出更多好玩的程序、实现更多酷炫的功能。

在日常生活中,我们经常需要记录从图片中提取的文字。比如名片信息、证件信息扫描等。

在下节课,我们将学习从图片中智能提取文本内容的技术,即

光学字符识别技术(OCR)。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。