Maison > Article > Applet WeChat > Voyons à quel point tu es belle ! Compte public développé sur la base de Python
Il s'agit d'un développement de compte public WeChat basé sur Python pour la détection d'apparence. Aujourd'hui, nous analysons les photos de l'utilisateur via la plate-forme d'IA de Tencent, puis les renvoyons à l'utilisateur. Vivons ensemble le test beauté des comptes publics
Jetons d'abord un coup d'œil à la description de l'interface officielle de détection et d'analyse des visages :
Détecter tous les visages (Face) dans un emplacement d'image (Image) donné et attributs du visage correspondants. La position comprend (x, y, w, h) et les attributs du visage incluent le sexe, l'âge, l'expression, la beauté, les lunettes et la posture (tangage, roulis, lacet).
Les paramètres de la demande incluent les éléments suivants :
identification de l'application app_id, nous pouvons obtenir l'app_id après l'inscription sur la plateforme AI
time_stamp timestamp
nonce_str chaîne aléatoire
signer les informations de signature, nous devons les calculer nous-mêmes
image Image à détecter (limite supérieure 1M)
mode de détection
Le responsable nous a donné la méthode de calcul de l'authentification de l'interface.
Triez les paires de paramètres de requête
Les paires de paramètres de la liste N sont fusionnées en chaînes au format de paires clé-valeur d'URL pour obtenir la chaîne T (par exemple : clé1=valeur1&clé2=valeur2). La partie valeur du processus d'épissage clé-valeur d'URL nécessite un codage d'URL. . L'algorithme de codage d'URL utilise des lettres majuscules. Par exemple, %E8, au lieu de %e8 minuscule
, utilisez app_key comme nom de clé pour former la valeur de clé d'URL et l'associer à la clé. fin de la chaîne T pour obtenir la chaîne S (comme : key1 =value1&key2=value2&app_key=Key)
Effectuer l'opération MD5 sur la chaîne S, convertir tous les caractères de la valeur MD5 obtenue en majuscules et obtenez la signature de la demande d'interface
Demander les informations de l'interface Nous utilisons des requêtes pour envoyer la demande, et nous obtiendrons. les informations d'image renvoyées au format json pip install requests
Demandes d'installation.
Traitez les informations renvoyées, affichez les informations sur l'image, puis enregistrez l'image traitée. Ici, nous utilisons les bibliothèques opencv et Pillow pip install pillow
et pip install opencv-python
pour installer.
Commençons à écrire du code. Nous créons un nouveau fichier face_id.py pour nous connecter à la plateforme AI et renvoyer les données d'image détectées.
import time import random import base64 import hashlib import requests from urllib.parse import urlencode import cv2 import numpy as np from PIL import Image, ImageDraw, ImageFont import os # 一.计算接口鉴权,构造请求参数 def random_str(): '''得到随机字符串nonce_str''' str = 'abcdefghijklmnopqrstuvwxyz' r = '' for i in range(15): index = random.randint(0,25) r += str[index] return r def image(name): with open(name, 'rb') as f: content = f.read() return base64.b64encode(content) def get_params(img): '''组织接口请求的参数形式,并且计算sign接口鉴权信息, 最终返回接口请求所需要的参数字典''' params = { 'app_id': '1106860829', 'time_stamp': str(int(time.time())), 'nonce_str': random_str(), 'image': img, 'mode': '0' } sort_dict = sorted(params.items(), key=lambda item: item[0], reverse=False) # 排序 sort_dict.append(('app_key', 'P8Gt8nxi6k8vLKbS')) # 添加app_key rawtext = urlencode(sort_dict).encode() # URL编码 sha = hashlib.md5() sha.update(rawtext) md5text = sha.hexdigest().upper() # 计算出sign,接口鉴权 params['sign'] = md5text # 添加到请求参数列表中 return params # 二.请求接口URL def access_api(img): frame = cv2.imread(img) nparry_encode = cv2.imencode('.jpg', frame)[1] data_encode = np.array(nparry_encode) img_encode = base64.b64encode(data_encode) # 图片转为base64编码格式 url = 'https://api.ai.qq.com/fcgi-bin/face/face_detectface' res = requests.post(url, get_params(img_encode)).json() # 请求URL,得到json信息 # 把信息显示到图片上 if res['ret'] == 0: # 0代表请求成功 pil_img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # 把opencv格式转换为PIL格式,方便写汉字 draw = ImageDraw.Draw(pil_img) for obj in res['data']['face_list']: img_width = res['data']['image_width'] # 图像宽度 img_height = res['data']['image_height'] # 图像高度 # print(obj) x = obj['x'] # 人脸框左上角x坐标 y = obj['y'] # 人脸框左上角y坐标 w = obj['width'] # 人脸框宽度 h = obj['height'] # 人脸框高度 # 根据返回的值,自定义一下显示的文字内容 if obj['glass'] == 1: # 眼镜 glass = '有' else: glass = '无' if obj['gender'] >= 70: # 性别值从0-100表示从女性到男性 gender = '男' elif 50 <= obj['gender'] < 70: gender = "娘" elif obj['gender'] < 30: gender = '女' else: gender = '女汉子' if 90 < obj['expression'] <= 100: # 表情从0-100,表示笑的程度 expression = '一笑倾城' elif 80 < obj['expression'] <= 90: expression = '心花怒放' elif 70 < obj['expression'] <= 80: expression = '兴高采烈' elif 60 < obj['expression'] <= 70: expression = '眉开眼笑' elif 50 < obj['expression'] <= 60: expression = '喜上眉梢' elif 40 < obj['expression'] <= 50: expression = '喜气洋洋' elif 30 < obj['expression'] <= 40: expression = '笑逐颜开' elif 20 < obj['expression'] <= 30: expression = '似笑非笑' elif 10 < obj['expression'] <= 20: expression = '半嗔半喜' elif 0 <= obj['expression'] <= 10: expression = '黯然伤神' delt = h // 5 # 确定文字垂直距离 # 写入图片 if len(res['data']['face_list']) > 1: # 检测到多个人脸,就把信息写入人脸框内 font = ImageFont.truetype('yahei.ttf', w // 8, encoding='utf-8') # 提前把字体文件下载好 draw.text((x + 10, y + 10), '性别 :' + gender, (76, 176, 80), font=font) draw.text((x + 10, y + 10 + delt * 1), '年龄 :' + str(obj['age']), (76, 176, 80), font=font) draw.text((x + 10, y + 10 + delt * 2), '表情 :' + expression, (76, 176, 80), font=font) draw.text((x + 10, y + 10 + delt * 3), '魅力 :' + str(obj['beauty']), (76, 176, 80), font=font) draw.text((x + 10, y + 10 + delt * 4), '眼镜 :' + glass, (76, 176, 80), font=font) elif img_width - x - w < 170: # 避免图片太窄,导致文字显示不完全 font = ImageFont.truetype('yahei.ttf', w // 8, encoding='utf-8') draw.text((x + 10, y + 10), '性别 :' + gender, (76, 176, 80), font=font) draw.text((x + 10, y + 10 + delt * 1), '年龄 :' + str(obj['age']), (76, 176, 80), font=font) draw.text((x + 10, y + 10 + delt * 2), '表情 :' + expression, (76, 176, 80), font=font) draw.text((x + 10, y + 10 + delt * 3), '魅力 :' + str(obj['beauty']), (76, 176, 80), font=font) draw.text((x + 10, y + 10 + delt * 4), '眼镜 :' + glass, (76, 176, 80), font=font) else: font = ImageFont.truetype('yahei.ttf', 20, encoding='utf-8') draw.text((x + w + 10, y + 10), '性别 :' + gender, (76, 176, 80), font=font) draw.text((x + w + 10, y + 10 + delt * 1), '年龄 :' + str(obj['age']), (76, 176, 80), font=font) draw.text((x + w + 10, y + 10 + delt * 2), '表情 :' + expression, (76, 176, 80), font=font) draw.text((x + w + 10, y + 10 + delt * 3), '魅力 :' + str(obj['beauty']), (76, 176, 80), font=font) draw.text((x + w + 10, y + 10 + delt * 4), '眼镜 :' + glass, (76, 176, 80), font=font) draw.rectangle((x, y, x + w, y + h), outline="#4CB050") # 画出人脸方框 cv2img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) # 把 pil 格式转换为 cv cv2.imwrite('faces/{}'.format(os.path.basename(img)), cv2img) # 保存图片到 face 文件夹下 return '检测成功' else: return '检测失败'
À ce stade, l'accès à notre interface de détection de visage et le traitement des images sont terminés. Après avoir reçu les informations d'image envoyées par l'utilisateur, appelez cette fonction et renvoyez l'image traitée à l'utilisateur.
Lors de la réception de la photo de l'utilisateur, les étapes suivantes sont requises :
Après avoir reçu la photo de l'utilisateur , Nous devons d'abord enregistrer l'image, puis nous pouvons appeler l'interface d'analyse du visage et transmettre les informations sur l'image. Nous devons écrire une fonction img_download pour télécharger l'image. Voir le code ci-dessous pour plus de détails
Après avoir téléchargé l'image, appelez la fonction d'interface dans le fichier face_id.py pour obtenir l'image traitée.
Le résultat de la détection est une nouvelle image. Pour envoyer l'image à l'utilisateur, nous avons besoin d'un Media_ID. Pour obtenir le Media_ID, nous devons d'abord télécharger l'image en tant que matériau temporaire. , donc ici nous avons besoin d'une fonction img_upload qui est utilisée pour télécharger des images, et un access_token est requis lors du téléchargement. Nous l'obtenons via une fonction Pour obtenir le access_token, nous devons ajouter notre propre adresse IP à la liste blanche, sinon elle. ne sera pas obtenu. Veuillez vous connecter à « WeChat Public Platform-Development-Basic Configuration » pour ajouter l'adresse IP du serveur à la liste blanche IP à l'avance. Vous pouvez afficher l'adresse IP de cette machine sur http://ip.qq.com/...<.>
Commençons à écrire du code, nous créons un nouveau utils.py pour télécharger et télécharger des imagesimport requests import json import threading import time import os token = '' app_id = 'wxfc6adcdd7593a712' secret = '429d85da0244792be19e0deb29615128' def img_download(url, name): r = requests.get(url) with open('images/{}-{}.jpg'.format(name, time.strftime("%Y_%m_%d%H_%M_%S", time.localtime())), 'wb') as fd: fd.write(r.content) if os.path.getsize(fd.name) >= 1048576: return 'large' # print('namename', os.path.basename(fd.name)) return os.path.basename(fd.name) def get_access_token(appid, secret): '''获取access_token,100分钟刷新一次''' url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}'.format(appid, secret) r = requests.get(url) parse_json = json.loads(r.text) global token token = parse_json['access_token'] global timer timer = threading.Timer(6000, get_access_token) timer.start() def img_upload(mediaType, name): global token url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=%s&type=%s" % (token, mediaType) files = {'media': open('{}'.format(name), 'rb')} r = requests.post(url, files=files) parse_json = json.loads(r.text) return parse_json['media_id'] get_access_token(app_id, secret)Retour à l'utilisateurNous modifions simplement la logique après réception l'image. Après détection du visage et téléchargement pour obtenir le Media_ID, il ne reste plus qu'à restituer l'image à l'utilisateur. Regardez directement le code de connect.py
import falcon from falcon import uri from wechatpy.utils import check_signature from wechatpy.exceptions import InvalidSignatureException from wechatpy import parse_message from wechatpy.replies import TextReply, ImageReply from utils import img_download, img_upload from face_id import access_api class Connect(object): def on_get(self, req, resp): query_string = req.query_string query_list = query_string.split('&') b = {} for i in query_list: b[i.split('=')[0]] = i.split('=')[1] try: check_signature(token='lengxiao', signature=b['signature'], timestamp=b['timestamp'], nonce=b['nonce']) resp.body = (b['echostr']) except InvalidSignatureException: pass resp.status = falcon.HTTP_200 def on_post(self, req, resp): xml = req.stream.read() msg = parse_message(xml) if msg.type == 'text': reply = TextReply(content=msg.content, message=msg) xml = reply.render() resp.body = (xml) resp.status = falcon.HTTP_200 elif msg.type == 'image': name = img_download(msg.image, msg.source) # 下载图片 r = access_api('images/' + name) if r == '检测成功': media_id = img_upload('image', 'faces/' + name) # 上传图片,得到 media_id reply = ImageReply(media_id=media_id, message=msg) else: reply = TextReply(content='人脸检测失败,请上传1M以下人脸清晰的照片', message=msg) xml = reply.render() resp.body = (xml) resp.status = falcon.HTTP_200 app = falcon.API() connect = Connect() app.add_route('/connect', connect)À ce stade, notre travail est terminé et notre compte officiel peut être testé pour son apparence. J'avais initialement prévu de l'utiliser sur mon compte officiel, mais il y a encore plusieurs problèmes ci-dessous, donc je ne l'ai pas utilisé.
Mécanisme de WeChat, notre programme doit répondre dans les 5 secondes. Sinon, il signalera « Le service fourni par le compte officiel est défectueux ». Cependant, le traitement des images est parfois lent, dépassant souvent les 5 secondes. Par conséquent, la bonne façon de le gérer devrait être de renvoyer immédiatement une chaîne vide après avoir reçu la demande de l'utilisateur pour indiquer que nous l'avons reçue, puis de créer un thread séparé pour traiter l'image. Lorsque l'image est traitée, elle est envoyée. l'utilisateur via l'interface du service client. Malheureusement, les comptes publics non certifiés n'ont pas d'interface de service client, vous ne pouvez donc rien faire. Si cela prend plus de 5 secondes, une erreur sera signalée.
Le menu ne peut pas être personnalisé. Une fois le développement personnalisé activé, le menu doit également être personnalisé. Cependant, les comptes publics non certifiés n'ont pas l'autorisation de configurer le menu via le programme et peuvent le faire. configurez-le uniquement dans la configuration du backend WeChat.
Donc, je n'ai pas activé ce programme sur mon compte officiel, mais si vous avez un compte officiel certifié, vous pouvez essayer de développer diverses fonctions amusantes.
Recommandations associées :
Tentative de développement de la plateforme publique WeChat , Plateforme publique WeChat
Vidéo : Tutoriel vidéo de développement de la plateforme publique Chuanzhi et Dark Horse WeChat
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!