1
+ import time
2
+ import random
3
+ import base64
4
+ import hashlib
5
+ import requests
6
+ from urllib .parse import urlencode
7
+ import cv2
8
+ import numpy as np
9
+ from PIL import Image , ImageDraw , ImageFont
10
+ import os
11
+
12
+
13
+ # 一.计算接口鉴权,构造请求参数
14
+
15
+ def random_str ():
16
+ '''得到随机字符串nonce_str'''
17
+ str = 'abcdefghijklmnopqrstuvwxyz'
18
+ r = ''
19
+ for i in range (15 ):
20
+ index = random .randint (0 ,25 )
21
+ r += str [index ]
22
+ return r
23
+
24
+
25
+ def image (name ):
26
+ with open (name , 'rb' ) as f :
27
+ content = f .read ()
28
+ return base64 .b64encode (content )
29
+
30
+
31
+ def get_params (img ):
32
+ '''组织接口请求的参数形式,并且计算sign接口鉴权信息,
33
+ 最终返回接口请求所需要的参数字典'''
34
+ params = {
35
+ 'app_id' : '1106860829' ,
36
+ 'time_stamp' : str (int (time .time ())),
37
+ 'nonce_str' : random_str (),
38
+ 'image' : img ,
39
+ 'mode' : '0'
40
+
41
+ }
42
+
43
+ sort_dict = sorted (params .items (), key = lambda item : item [0 ], reverse = False ) # 排序
44
+ sort_dict .append (('app_key' , 'P8Gt8nxi6k8vLKbS' )) # 添加app_key
45
+ rawtext = urlencode (sort_dict ).encode () # URL编码
46
+ sha = hashlib .md5 ()
47
+ sha .update (rawtext )
48
+ md5text = sha .hexdigest ().upper () # 计算出sign,接口鉴权
49
+ params ['sign' ] = md5text # 添加到请求参数列表中
50
+ return params
51
+
52
+ # 二.请求接口URL
53
+
54
+
55
+ def access_api (img ):
56
+ print (img )
57
+ frame = cv2 .imread (img )
58
+ nparry_encode = cv2 .imencode ('.jpg' , frame )[1 ]
59
+ data_encode = np .array (nparry_encode )
60
+ img_encode = base64 .b64encode (data_encode ) # 图片转为base64编码格式
61
+ url = 'https://api.ai.qq.com/fcgi-bin/face/face_detectface'
62
+ res = requests .post (url , get_params (img_encode )).json () # 请求URL,得到json信息
63
+ # 把信息显示到图片上
64
+ if res ['ret' ] == 0 : # 0代表请求成功
65
+ pil_img = Image .fromarray (cv2 .cvtColor (frame , cv2 .COLOR_BGR2RGB )) # 把opencv格式转换为PIL格式,方便写汉字
66
+ draw = ImageDraw .Draw (pil_img )
67
+ for obj in res ['data' ]['face_list' ]:
68
+ img_width = res ['data' ]['image_width' ] # 图像宽度
69
+ img_height = res ['data' ]['image_height' ] # 图像高度
70
+ # print(obj)
71
+ x = obj ['x' ] # 人脸框左上角x坐标
72
+ y = obj ['y' ] # 人脸框左上角y坐标
73
+ w = obj ['width' ] # 人脸框宽度
74
+ h = obj ['height' ] # 人脸框高度
75
+ # 根据返回的值,自定义一下显示的文字内容
76
+ if obj ['glass' ] == 1 : # 眼镜
77
+ glass = '有'
78
+ else :
79
+ glass = '无'
80
+ if obj ['gender' ] >= 70 : # 性别值从0-100表示从女性到男性
81
+ gender = '男'
82
+ elif 50 <= obj ['gender' ] < 70 :
83
+ gender = "娘"
84
+ elif obj ['gender' ] < 30 :
85
+ gender = '女'
86
+ else :
87
+ gender = '女汉子'
88
+ if 90 < obj ['expression' ] <= 100 : # 表情从0-100,表示笑的程度
89
+ expression = '一笑倾城'
90
+ elif 80 < obj ['expression' ] <= 90 :
91
+ expression = '心花怒放'
92
+ elif 70 < obj ['expression' ] <= 80 :
93
+ expression = '兴高采烈'
94
+ elif 60 < obj ['expression' ] <= 70 :
95
+ expression = '眉开眼笑'
96
+ elif 50 < obj ['expression' ] <= 60 :
97
+ expression = '喜上眉梢'
98
+ elif 40 < obj ['expression' ] <= 50 :
99
+ expression = '喜气洋洋'
100
+ elif 30 < obj ['expression' ] <= 40 :
101
+ expression = '笑逐颜开'
102
+ elif 20 < obj ['expression' ] <= 30 :
103
+ expression = '似笑非笑'
104
+ elif 10 < obj ['expression' ] <= 20 :
105
+ expression = '半嗔半喜'
106
+ elif 0 <= obj ['expression' ] <= 10 :
107
+ expression = '黯然伤神'
108
+ delt = h // 5 # 确定文字垂直距离
109
+ # 写入图片
110
+ if len (res ['data' ]['face_list' ]) > 1 : # 检测到多个人脸,就把信息写入人脸框内
111
+ font = ImageFont .truetype ('yahei.ttf' , w // 8 , encoding = 'utf-8' ) # 提前把字体文件下载好
112
+ draw .text ((x + 10 , y + 10 ), '性别 :' + gender , (76 , 176 , 80 ), font = font )
113
+ draw .text ((x + 10 , y + 10 + delt * 1 ), '年龄 :' + str (obj ['age' ]), (76 , 176 , 80 ), font = font )
114
+ draw .text ((x + 10 , y + 10 + delt * 2 ), '表情 :' + expression , (76 , 176 , 80 ), font = font )
115
+ draw .text ((x + 10 , y + 10 + delt * 3 ), '魅力 :' + str (obj ['beauty' ]), (76 , 176 , 80 ), font = font )
116
+ draw .text ((x + 10 , y + 10 + delt * 4 ), '眼镜 :' + glass , (76 , 176 , 80 ), font = font )
117
+ elif img_width - x - w < 170 : # 避免图片太窄,导致文字显示不完全
118
+ font = ImageFont .truetype ('yahei.ttf' , w // 8 , encoding = 'utf-8' )
119
+ draw .text ((x + 10 , y + 10 ), '性别 :' + gender , (76 , 176 , 80 ), font = font )
120
+ draw .text ((x + 10 , y + 10 + delt * 1 ), '年龄 :' + str (obj ['age' ]), (76 , 176 , 80 ), font = font )
121
+ draw .text ((x + 10 , y + 10 + delt * 2 ), '表情 :' + expression , (76 , 176 , 80 ), font = font )
122
+ draw .text ((x + 10 , y + 10 + delt * 3 ), '魅力 :' + str (obj ['beauty' ]), (76 , 176 , 80 ), font = font )
123
+ draw .text ((x + 10 , y + 10 + delt * 4 ), '眼镜 :' + glass , (76 , 176 , 80 ), font = font )
124
+ else :
125
+ font = ImageFont .truetype ('yahei.ttf' , 20 , encoding = 'utf-8' )
126
+ draw .text ((x + w + 10 , y + 10 ), '性别 :' + gender , (76 , 176 , 80 ), font = font )
127
+ draw .text ((x + w + 10 , y + 10 + delt * 1 ), '年龄 :' + str (obj ['age' ]), (76 , 176 , 80 ), font = font )
128
+ draw .text ((x + w + 10 , y + 10 + delt * 2 ), '表情 :' + expression , (76 , 176 , 80 ), font = font )
129
+ draw .text ((x + w + 10 , y + 10 + delt * 3 ), '魅力 :' + str (obj ['beauty' ]), (76 , 176 , 80 ), font = font )
130
+ draw .text ((x + w + 10 , y + 10 + delt * 4 ), '眼镜 :' + glass , (76 , 176 , 80 ), font = font )
131
+
132
+ draw .rectangle ((x , y , x + w , y + h ), outline = "#4CB050" ) # 画出人脸方框
133
+ cv2img = cv2 .cvtColor (np .array (pil_img ), cv2 .COLOR_RGB2BGR ) # 把 pil 格式转换为 cv
134
+ cv2 .imwrite ('faces/{}' .format (os .path .basename (img )), cv2img ) # 保存图片到 face 文件夹下
135
+ return '检测成功'
136
+ else :
137
+ return '检测失败'
0 commit comments