全国最佳python趣味性项目,让人工智能给你的颜值打个分!
在是人工智能兴起的时代,到处都在谈人工智能。今天就从人工智能的角度给你的颜值打个分。
在这里,我会把整个实现过程写出来。
先介绍一下用到了哪些东西(用Python3实现)
- 百度的人脸识别api
- Flask
- PIL
- requests
操作很简单,主要是利用的百度的人脸识别库,然后自己做了一个简单的图片上传和图片处理以及信息提取加工。
百度的人脸识别api申请的地址,需要有百度账号: 传送门
然后在控制台创建一个应用即可:
创建应用
在应用列表中可以看到你创建的应用:
应用列表
通过查看百度的人脸识别的文档,我们就可以写代码了。
想要使用百度的api,申请只是第一步,后面还需要获取access_token,文档给出的方法如下:
用方法
官网给的方法相对比较繁琐,我使用request改写了一下如下(注意把url里面的Key换成你申请的)。
<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">def get_access_token():
url = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&grant_type=client_credentials&' 'client_id=【你申请的API Key】&client_secret=【你申请的Secret Key】'
data = requests.get(url, headers).json() return data['access_token']
</pre>
拿到这个key之后,就可以进行下一步的请求了,继续看文档:
请求文档
文档中说要使用post方法进行请求,请求的url给出了,url的参数是上面获取到的access_token,请求的头部要包含”Content-Type”: “application/json”
下面是主体部分,也就是对上传的图片的要求,以及你想要获取的内容的一下说明:
请求参数
文档说图片的大小不能大于10M,上传的类型包含三种,一种是URL。还有就是图片通过Base64编码后得到的编码信息。其中face_field是你想要返回的内容等等,文档里面说的都很清楚,这里不做过多介绍。
首先,我们不采用图片url的方式,我们直接使用对图片进行base64编码的形式进行处理。编码的过程如下:
<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">with open('static/' + filename, 'rb') as f:
base = base64.b64encode(f.read())
image = str(base, encoding='utf-8')
</pre>
请求的参数构造如下:
<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">params = { 'image': image, 'image_type': imageType, 'face_field': 'age,beauty,gender,face_type,face_shape,expression,landmark'}
</pre>
其中image是我们上面编码过的结果,imageType是BASE64,face_field是我们想要它返回给我们的内容,包括年龄,颜值,性别,人物类型,脸型,表情,检测的点。
然后通过返回给我们的数据,提取(完整代码如下)相应的内容:
<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">def get_content(filename):
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token="+get_access_token() with open('static/' + filename, 'rb') as f:
base = base64.b64encode(f.read())
image = str(base, encoding='utf-8')
params = { 'image': image, 'image_type': imageType, 'face_field': 'age,beauty,gender,face_type,face_shape,expression,landmark'
}
info = requests.post(request_url, headers=headers, data=params).json() if info['error_msg'] == 'SUCCESS': # 用于判断是否检测到人脸
face = info['result']['face_num'] # 年龄, 人脸, 性别
age = info['result']['face_list'][0]['age']
beauty = info['result']['face_list'][0]['beauty'] # male, female
gender = info['result']['face_list'][0]['gender']['type'] # none 不笑, smile 微笑, laugh 大笑
expression = info['result']['face_list'][0]['expression']['type'] # square 正方形, triangle 三角形, oval 椭圆, heart 心形, round 圆形
face_shape = info['result']['face_list'][0]['face_shape']['type']
fs = { 'square': '方型脸', 'triangle': '瓜子脸', 'oval': '圆型脸', 'heart': '瓜子脸', 'round': '圆型脸'
} # human 真实人脸, cartoon 卡通人脸
face_type = info['result']['face_list'][0]['face_type']['type']
landmark72 = info['result']['face_list'][0]['landmark72']
img = Image.open('static/' + filename)
draw = ImageDraw.Draw(img) for idx in range(72):
xy = landmark72[idx]
draw.text((xy['x'], xy['y']), 'o', (255, 255, 0))
ImageDraw.Draw(img)
img.save('static/new_' + filename) if face is 1:
data = { 'age': age, 'beauty': str(round(beauty, 3)) + ' (不要灰心, 换个姿势再试试)' if beauty < 60 else str(round(beauty, 3)) + ' (哇塞! 颜值很高啊)', 'gender': '美女你好' if 'female' in gender else '帅哥你好', 'expression': '面无表情(记得要常笑哦)' if 'none' in expression else '微笑' if 'smile' in expression else '大笑(什么事这么开心)', 'face_shape': fs[face_shape], 'face_type': '真实人物' if 'human' in face_type else '卡通人物'
} return data else: return '未识别出人脸, 上传的图片尽量不要有遮盖住脸!!!'
</pre>
代码中已经给了相应的注释,其中没给注释的一部分是通过提取的72个关键点,然后通过循环,把这些坐标点通过ImageDraw画到了图片上面。下面是返回的info的数据:
info
下面是我们从中提取的信息:
提取的内容
这样我们的基本工作就算完成了,但是这样并不完善,我们打算把它做成Web的形式,这样所有人就都可以用了,Web的话Python主流有Django、Flask、Tornado等,这里我们选择了Flask,主要是它轻量化也比较简单。
主要通过flask_uploads库实现文件上传,该库的具体用法,大家可以自行去了解。
文件上传
首先接收上传的图片(通过UploadSet指定只接收Images类型),如果是GET类型,就返回上传的html,如果是POST类型,并且包含photo,就接收上传,通过securefilename,去检查上传图片的安全性,然后再对上传的图片通过时间戳重命名,然后调用我们前面写的get_content, 把图片的地址传给它,就可以进行处理了。
result.html的内容如下:
<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><!DOCTYPE html><html lang="en"><head>
<meta charset="UTF-8" name="viewport" content="width=device-width, initial-scale=1" />
<title>人脸识别</title></head><body style="background: beige">
<div align="center">
<form method="post" enctype="multipart/form-data">
<input type="file" name="photo">
<input type="submit" value="提交">
</form>
</div>
{% if '未识别' not in content and content%} <div align="center" style="padding-top: 30px">
<p><img src="{{ file_url }}" width="150"> {% if new_url %}<img src="{{ new_url }}" width="150">{% endif %}</p>
<table border="0" align="center" cellpadding="5" cellspacing="0">
<tr>
<td align="right">年龄: </td>
<td align="left" style="color:red;">{{ content['age'] }}</td>
</tr>
<tr>
<td align="right">颜值: </td>
<td align="left" style="color:red;">{{ content['beauty'] }}</td>
</tr>
<tr>
<td align="right">性别: </td>
<td align="left" style="color:red;">{{ content['gender'] }}</td>
</tr>
<tr>
<td align="right">表情: </td>
<td align="left" style="color:red;">{{ content['expression'] }}</td>
</tr>
<tr>
<td align="right">脸型: </td>
<td align="left" style="color:red;">{{ content['face_shape'] }}</td>
</tr>
<tr>
<td align="right">人物类型: </td>
<td align="left" style="color:red;">{{ content['face_type'] }}</td>
</tr>
</table>
</div>
{% else %} <h1 align="center" style="color: red">{{ content }}</h1>
{% endif %}</body></html>
</pre>
使用Jinja2模板(前端设计的有点简陋,大家将就的看),把前面提取到的内容传给它,然后通过网页的形式展示出来。
效果如下(主要打算在手机端运行,所以电脑端看起来可能有点怪异):
手机端的效果如下
用着百度的东西,又把李彦宏拉出来可能有点不太厚道,不过AI给它的颜值评的分还算可以。是亲生的。