Maison  >  Article  >  Applet WeChat  >  Voyons à quel point tu es belle ! Compte public développé sur la base de Python

Voyons à quel point tu es belle ! Compte public développé sur la base de Python

php是最好的语言
php是最好的语言original
2018-07-25 13:56:172426parcourir

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

Rendu

Voyons à quel point tu es belle ! Compte public développé sur la base de Python

Voyons à quel point tu es belle ! Compte public développé sur la base de Python

Voyons à quel point tu es belle ! Compte public développé sur la base de Python

1 . Accès à la plateforme Tencent AI

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

1.

Le responsable nous a donné la méthode de calcul de l'authentification de l'interface.

  1. Triez les paires de paramètres de requête dans l'ordre croissant du dictionnaire par clé pour obtenir une liste ordonnée de paires de paramètres N

  2. 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

  3. , 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)

  4. 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

2. Demander l'adresse de l'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 requestsDemandes d'installation.

3. Traitez les informations renvoyées

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[&#39;gender&#39;] < 70:
                gender = "娘"
            elif obj[&#39;gender&#39;] < 30:
                gender = &#39;女&#39;
            else:
                gender = &#39;女汉子&#39;
            if 90 < obj[&#39;expression&#39;] <= 100:  # 表情从0-100,表示笑的程度
                expression = &#39;一笑倾城&#39;
            elif 80 < obj[&#39;expression&#39;] <= 90:
                expression = &#39;心花怒放&#39;
            elif 70 < obj[&#39;expression&#39;] <= 80:
                expression = &#39;兴高采烈&#39;
            elif 60 < obj[&#39;expression&#39;] <= 70:
                expression = &#39;眉开眼笑&#39;
            elif 50 < obj[&#39;expression&#39;] <= 60:
                expression = &#39;喜上眉梢&#39;
            elif 40 < obj[&#39;expression&#39;] <= 50:
                expression = &#39;喜气洋洋&#39;
            elif 30 < obj[&#39;expression&#39;] <= 40:
                expression = &#39;笑逐颜开&#39;
            elif 20 < obj[&#39;expression&#39;] <= 30:
                expression = &#39;似笑非笑&#39;
            elif 10 < obj[&#39;expression&#39;] <= 20:
                expression = &#39;半嗔半喜&#39;
            elif 0 <= obj[&#39;expression&#39;] <= 10:
                expression = &#39;黯然伤神&#39;
            delt = h // 5  # 确定文字垂直距离
            # 写入图片
            if len(res[&#39;data&#39;][&#39;face_list&#39;]) > 1:  # 检测到多个人脸,就把信息写入人脸框内
                font = ImageFont.truetype(&#39;yahei.ttf&#39;, w // 8, encoding=&#39;utf-8&#39;)  # 提前把字体文件下载好
                draw.text((x + 10, y + 10), &#39;性别 :&#39; + gender, (76, 176, 80), font=font)
                draw.text((x + 10, y + 10 + delt * 1), &#39;年龄 :&#39; + str(obj[&#39;age&#39;]), (76, 176, 80), font=font)
                draw.text((x + 10, y + 10 + delt * 2), &#39;表情 :&#39; + expression, (76, 176, 80), font=font)
                draw.text((x + 10, y + 10 + delt * 3), &#39;魅力 :&#39; + str(obj[&#39;beauty&#39;]), (76, 176, 80), font=font)
                draw.text((x + 10, y + 10 + delt * 4), &#39;眼镜 :&#39; + glass, (76, 176, 80), font=font)
            elif img_width - x - w < 170:  # 避免图片太窄,导致文字显示不完全
                font = ImageFont.truetype(&#39;yahei.ttf&#39;, w // 8, encoding=&#39;utf-8&#39;)
                draw.text((x + 10, y + 10), &#39;性别 :&#39; + gender, (76, 176, 80), font=font)
                draw.text((x + 10, y + 10 + delt * 1), &#39;年龄 :&#39; + str(obj[&#39;age&#39;]), (76, 176, 80), font=font)
                draw.text((x + 10, y + 10 + delt * 2), &#39;表情 :&#39; + expression, (76, 176, 80), font=font)
                draw.text((x + 10, y + 10 + delt * 3), &#39;魅力 :&#39; + str(obj[&#39;beauty&#39;]), (76, 176, 80), font=font)
                draw.text((x + 10, y + 10 + delt * 4), &#39;眼镜 :&#39; + glass, (76, 176, 80), font=font)
            else:
                font = ImageFont.truetype(&#39;yahei.ttf&#39;, 20, encoding=&#39;utf-8&#39;)
                draw.text((x + w + 10, y + 10), &#39;性别 :&#39; + gender, (76, 176, 80), font=font)
                draw.text((x + w + 10, y + 10 + delt * 1), &#39;年龄 :&#39; + str(obj[&#39;age&#39;]), (76, 176, 80), font=font)
                draw.text((x + w + 10, y + 10 + delt * 2), &#39;表情 :&#39; + expression, (76, 176, 80), font=font)
                draw.text((x + w + 10, y + 10 + delt * 3), &#39;魅力 :&#39; + str(obj[&#39;beauty&#39;]), (76, 176, 80), font=font)
                draw.text((x + w + 10, y + 10 + delt * 4), &#39;眼镜 :&#39; + 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(&#39;faces/{}&#39;.format(os.path.basename(img)), cv2img)  # 保存图片到 face 文件夹下
            return &#39;检测成功&#39;
    else:
        return &#39;检测失败&#39;

À 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.

Renvoyer la photo à l'utilisateur

Lors de la réception de la photo de l'utilisateur, les étapes suivantes sont requises :

Enregistrer la photo

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

Appel de l'interface d'analyse du visage

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.

Télécharger l'image

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 images

import requests
import json
import threading
import time
import os

token = &#39;&#39;
app_id = &#39;wxfc6adcdd7593a712&#39;
secret = &#39;429d85da0244792be19e0deb29615128&#39;


def img_download(url, name):
    r = requests.get(url)
    with open(&#39;images/{}-{}.jpg&#39;.format(name, time.strftime("%Y_%m_%d%H_%M_%S", time.localtime())), &#39;wb&#39;) as fd:
        fd.write(r.content)
    if os.path.getsize(fd.name) >= 1048576:
        return &#39;large&#39;
    # print(&#39;namename&#39;, os.path.basename(fd.name))
    return os.path.basename(fd.name)


def get_access_token(appid, secret):
    &#39;&#39;&#39;获取access_token,100分钟刷新一次&#39;&#39;&#39;

    url = &#39;https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}&#39;.format(appid, secret)
    r = requests.get(url)
    parse_json = json.loads(r.text)
    global token
    token = parse_json[&#39;access_token&#39;]
    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 = {&#39;media&#39;: open(&#39;{}&#39;.format(name), &#39;rb&#39;)}
    r = requests.post(url, files=files)
    parse_json = json.loads(r.text)
    return parse_json[&#39;media_id&#39;]

get_access_token(app_id, secret)
Retour à l'utilisateur

Nous 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(&#39;&&#39;)
        b = {}
        for i in query_list:
            b[i.split(&#39;=&#39;)[0]] = i.split(&#39;=&#39;)[1]

        try:
            check_signature(token=&#39;lengxiao&#39;, signature=b[&#39;signature&#39;], timestamp=b[&#39;timestamp&#39;], nonce=b[&#39;nonce&#39;])
            resp.body = (b[&#39;echostr&#39;])
        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 == &#39;text&#39;:
            reply = TextReply(content=msg.content, message=msg)
            xml = reply.render()
            resp.body = (xml)
            resp.status = falcon.HTTP_200
        elif msg.type == &#39;image&#39;:
            name = img_download(msg.image, msg.source)  # 下载图片
            r = access_api(&#39;images/&#39; + name)
            if r == &#39;检测成功&#39;:
                media_id = img_upload(&#39;image&#39;, &#39;faces/&#39; + name)  # 上传图片,得到 media_id
                reply = ImageReply(media_id=media_id, message=msg)
            else:
                reply = TextReply(content=&#39;人脸检测失败,请上传1M以下人脸清晰的照片&#39;, message=msg)
            xml = reply.render()
            resp.body = (xml)
            resp.status = falcon.HTTP_200

app = falcon.API()
connect = Connect()
app.add_route(&#39;/connect&#39;, 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é.

  1. 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.

  2. 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 :

Développement de la plateforme publique WeChat Suivez en un clic le compte de la plateforme publique WeChat

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn