【class12】人工智能初步(人脸识别(3))

通过昨天的学习,我们已经完成了“口罩佩戴检测”系统的第一步——获取具有人脸识别功能的接口。
在今天的课程中,我们将学习如何对图像进行人脸检测,实现这个过程需要两步:
1. 使用base64编码方法将图片转换成字符串;
2. 使用detect方法进行人脸检测:
让我们先来学习第一步~

detect(人脸检测)接口要求图片必须使用base64编码
所以在开始使用detect接口前,先来学习一下将图片转化为字符串的方法——base64编码

BASE64编码

定义

Base64(基底64)是一种基于64个可打印字符来表示数据的方法,是一种编码方式。

隐喻

我们使用的拼音可以看作是一种基于26个可打印字符(26个字母)来表示所有汉字的方法。

Base64 编码

Base64 编码将二进制数据转化为指定的64个可读字符,这样做能够在一定程度上缩小数据的长度,方便记录存储。
数据不再是0、1组成的二进制,而是一些常用的字符。

                  

不仅如此,base64还可以将非文本内容如图片、视频等数据,转换为文本形式。
这在只支持文本传输的协议下,非常实用。

Base64---代码组成

完成这个过程的代码需要3步:
1. 打开并读取指定的图片文件;
2. 利用base64模块进行编码;
3. 将编码结果转化为字符串;

    

Ps

除了 r  rb,在 Python 中还有其他一些打开文件时可以使用的模式:

  1. w: 写入模式 (write mode)
    • 使用这种模式打开文件时,如果文件不存在,则创建文件;如果文件已经存在,则先清空文件内容,然后开始写入新的内容。

with open("example.txt", "w") as file:

file.write("Hello, world!")

a: 追加模式 (append mode)

2.使用这种模式打开文件时,如果文件不存在,则创建文件;如果文件已经存在,则将新的内容追加到文件的末尾。

with open("example.txt", "a") as file:

file.write("Appending new content!")

r+: 读写模式 (read-write mode)

3.使用这种模式打开文件时,可以同时读取和写入文件。文件的指针会位于文件的开头,可以读取和写入文件的任意位置。

with open("example.txt", "r+") as file:

    content = file.read()

file.write("\nAdding new content!")

w+: 读写模式 (write-read mode)

4.使用这种模式打开文件时,如果文件不存在,则创建文件;如果文件已经存在,则先清空文件内容,然后可以同时读取和写入文件。

with open("example.txt", "w+") as file:

    file.write("Writing and reading!")

    file.seek(0)  # 移动文件指针到文件开头

content = file.read()

a+: 追加和读取模式 (append-read mode)

5.使用这种模式打开文件时,如果文件不存在,则创建文件;如果文件已经存在,则可以在文件的末尾追加内容,并且可以读取文件内容。

with open("example.txt", "a+") as file:

    file.write("Appending and reading!")

    file.seek(0)  # 移动文件指针到文件开头

content = file.read()

这些是最常用的文件打开模式,它们可以根据需要进行组合使用,以满足不同的文件操作需求。

分析代码:

导入模块

导入base64模块,用来为程序提供base64编码的支持。
base64 为python自带的模块,不需要安装即可直接使用。

图片路径

设定图片路径。
选定要转换的图片位置,以字符串的形式存储在变量img_path中。

打开图片

使用open函数打开img_path路径下的图片,并存储在变量file中。
“rb” 是read binary 的缩写,指以读取二进制的模式打开文件。

读取内容

利用file的read()方法读取文件中的内容,并将二进制结果存储在res 变量中。

对数据进行base64编码

使用 base64.b64encode()函数,将res变量中的内容转换为base64编码后的数据。
并存储在img变量中。

将编码结果转化为字符串

编码后的数据还不能被detect接口直接使用,我们需要将它转换为字符串形式。

利用str()函数可以将数据强制转换为字符串。为了避免乱码,我们需要将img中的数据以一种通用的编码——“utf-8”,进行转换。

人脸检测(detect)的必选参数

完成了将图片转换为字符串的步骤,我们就得到了detect的两个必选的参数:

1. image

要识别的图片:图片的字符串数据

2. imageType

该图片的类型:BASE64

    

接下来,我们进入人脸检测的第二步,学习一下人脸检测接口detect()的用法。

创建客户端

通过昨天学习的内容,将应用密钥作为参数传递给 AipFace,生成提供人脸识别功能的客户端client。
通过client变量,可以使用人脸检测接口detect,即client.detect。

编码要检测的图片

通过base64,将图片文件转换为字符串。
转换后的结果存储在img变量中,该变量会作为client.detect方法传入的第一个参数。

设定图片的类型

设定图片类型为 BASE64 格式。
创建变量 img_type 用来存储待检测图片的类型"BASE64",这个变量会作为第二个参数传递给 client.detect

使用detect方法

存储图片的img变量与说明图片类型的img_type变量准备完成后,就可以调用 client.detect 方法进行人脸检测。

对指定一张图片进行人脸检测需要执行下面的步骤:

1. 获取被base64编码的图片数据;

2. 设定图片的类型"BASE64";

3. 将图片数据、类型传递给client.detect中,对人脸进行检测;

4. 提取检测结果中的信息,并输出。

注意:输出变量中的log_id是一个随机数,每次运行都会发生改变。

检测结果

接下来我们分析一下人脸检测得到的信息,它被存储在ret_data变量中。
输出该变量,用来获取存储:
【调用接口信息】;
【检测结果】;
两部分内容的字典。

调用接口信息

在 ret_data 字典中:
ret_data['error_code'] 记录错误代码,为0时,表示检测成功。
ret_data['error_msg'] 记录错误信息,'SUCCESS' 表示检测成功。

人脸检测结果

ret_data['result'] 用字典记录了人脸检测的结果,其中:
ret_data['result']['face_num'] 中记录识别到的人脸数量;
ret_data['result']['face_list'] 中用列表存储每张人脸的信息;

让我们对ret_data变量中的检测结果进行拆解:
1. 利用ret_data['error_msg']判断检测是否成功;
2. 利用ret_data['result']['face_num']获取人脸数量
3. 利用ret_data['result']['face_list']获取面孔信息

# 导入AipFace类

from aip import AipFace

# 以字符串的形式存储密钥

APP_ID = '10252021'

API_KEY = 'ZHe7788sh11GEjIAdEKeY'

SECRET_KEY = 'JMMzHe7788BUSH1ZhEnM1YUEhh'

# 将密钥信息传递给AipFace生成客户端,并将结果存储在client中

client = AipFace(APP_ID, API_KEY, SECRET_KEY)

# 导入base64模块

import base64

# 图片的路径

img_path = "/User/img/pic.png"

# 以rb的方式读取图片

with open(img_path, "rb") as file:

    # 读取图片内容

    res = file.read()

    # 图片文件进行base64编码

    img = base64.b64encode(res)

    # 图片转换为字符串

    img = str(img, 'utf-8')

   

# 设定图片类型为base64类型

img_type = "BASE64"

# 带参数调用人脸检测,识别结果命名为ret_data

ret_data = client.detect(img, img_type)

# 判断检测是否成功:错误信息是否为SUCCESS

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

    print('识别到的人脸数量为:')

    # 若检测成功,输出识别到的人脸数量

    print(ret_data['result']['face_num'])

    print('检测到的面孔信息:')

    # 输出面孔信息

    print(ret_data['result']['face_list'])

# 否则输出检测失败

else:

print('检测失败!')

识别到的人脸数量为

1

检测到的面孔信息

[{'face_token': 'cd3e33fe4c6066a843d15864513bfc8b', 'location': {'left': 287.07, 'top': 164.24, 'width': 73, 'height': 68, 'rotation': 25}, 'face_probability': 1, 'angle': {'yaw': -57.59, 'pitch': -0.55, 'roll': 22.8}}]

通过刚才的练习可以发现,现在的程序最多只能从图中识别到一个面孔信息。
这是因为AipFace的人脸检测功能默认只识别一个人脸信息,若要增大识别的数量,需要在使用detect时,传入 options 参数进行配置

Ps

options 参数

detect 提供一些可选的参数用来配置接口功能,它们被存储在名为options的字典中。
除了增加识别数量,options也提供诸如年龄检测、美丑打分、性别判断等其它属性识别的功能。

代码结构

options 参数以字典的形式存储配置信息。其中:
options['max_face_num'],配置最多识别的人脸数目为10;
options['face_field'],配置需要识别的面部属性为质量(quality)与年龄(age)。
它将作为第三个参数传递给client.detect。

       

分析代码:

options 字典

创建一个字典,并把它存储在变量options中。
options 字典中存储的配置信息,作为第三个参数传递给client.detect。

设置人脸数量

在 options 字典中,加入一个键为'max_face_num'的元素,该元素对应的整数值就是程序能够从图片中识别到的最多人脸数目。
max_face_num 可设置的范围为 1~10。

获取面部属性

在 options 字典中,加入一个键为'face_field'的元素,它的值为字符串存储的属性名称。
face_field 可以同时设置多种属性,名称之间以逗号隔开,且不能有空格。
在这里,我们配置了脸部信息的“识别质量”与“年龄”功能。

检查识别结果

输出识别到的人脸数目。
可以看到,添加了options参数以后,能够正常识别到图片中所有的人脸。

在使用detect接口时,可以通过options进行功能配置:
1. 创建字典options;
2. 为options字典添加max_face_num键,设置最大识别数;
3. 为options字典添加face_field键,设置面部属性;
4. 将options作为第3个参数传递给detect。

此时重新对图片进行检测,就可以检测到全部的人脸信息了

人脸属性信息

配置options参数不仅让我们成功检测到图中的所有面孔,并依次将每个面孔的【位置信息】、【检测质量】与【年龄预测】等信息,记录在ret_data['result']['face_list']这些字典中。

利用这些面孔信息, 接下来我们需要对程序进行优化,使检测结果可视化
比如,我们可以通过检测到的位置信息来修改图片,直接标注出人脸的位置。

下节预告

在下节课的学习中,我们将完成项目的第三部。
通过 Python 图片处理模块 pillow,将检测到的人脸位置,用矩形在图片中标注出来。

【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模块的结合,我们标记出了图中所有的面孔。
那么通过【检测质量】数据,我们能实现那些功能呢?

下节预告

在下节课的学习中,我们将利用这些数据来判断画面中人物的口罩佩戴情况。
也就是项目的最后一步——口罩佩戴情况检测。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值