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