赞
踩
通过昨天的学习,我们已经完成了“口罩佩戴检测”系统的第一步——获取具有人脸识别功能的接口。
在今天的课程中,我们将学习如何对图像进行人脸检测,实现这个过程需要两步:
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 中还有其他一些打开文件时可以使用的模式:
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模块的结合,我们标记出了图中所有的面孔。
那么通过【检测质量】数据,我们能实现那些功能呢?
下节预告
在下节课的学习中,我们将利用这些数据来判断画面中人物的口罩佩戴情况。
也就是项目的最后一步——口罩佩戴情况检测。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。