これは、外観検出のための Python ベースの WeChat パブリック アカウントの開発であり、現在、Tencent の AI プラットフォームを通じてユーザーの写真を分析し、ユーザーに返します。公開アカウントの額面検出を一緒に体験しましょう
まず、公式の顔検出および分析インターフェイスの説明を見てみましょう。
指定された画像内のすべての顔の位置と対応する顔属性を検出します。位置には (x、y、w、h) が含まれ、顔の属性には性別、年齢、表情、美しさ、眼鏡、姿勢 (ピッチ、ロール、ヨー) が含まれます。
リクエストパラメータには以下が含まれます:
app_id アプリケーション識別、AIプラットフォームに登録した後にapp_idを取得できます
time_stampタイムスタンプ
nonce_strランダム文字列
署名署名情報, 自分で計算する必要があります
検出するイメージ画像(上限1M)
モード検出モード
公式が計算方法を教えてくれました。インターフェース認証。
リスト N 内のパラメータペアを URL の形式に従って文字に結合しますキーと値のペア文字列を使用して文字列 T を取得します (例: key1=value1&key2=value2)。URL キーと値の結合プロセスの値部分では、URL エンコード アルゴリズムでは、代わりに %E8 などの大文字が使用されます。小文字の %e8
アプリケーションのパスワードは、キー名として app_key を使用し、URL キーの値が文字列 T の末尾に結合されて文字列 S が取得されます (例: key1=value1&key2) =value2&app_key=key)
文字列 S に対して MD5 操作を実行し、MD5 を取得します。 値のすべての文字を大文字に変換し、インターフェース要求署名を取得します
を要求します。インターフェイス情報。リクエストを送信するためにリクエストを使用し、返されたイメージ情報を json 形式で取得します。pip installrequests
インストール リクエスト。 pip install requests
安装requests。
处理返回的信息,把信息展示在图片上,再把处理后的图片保存。这里我们用到 opencv ,和 pillow 两个库pip install pillow
和pip install opencv-python
pip installpillow
および pip install opencv-python
をインストールに使用します。 AI プラットフォームに接続し、検出された画像データを返すための新しい face_id.py ファイルを作成します。 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 '检测失败'
画像をアップロード
検出結果は新しい画像です。画像をユーザーに送信するには Media_ID が必要です。Media_ID を取得するには、まず画像を一時素材としてアップロードする必要があります。そのため、ここでは img_upload 関数が必要です。写真をアップロードするには、access_token が必要であり、関数を通じて取得します。 access_token を取得するには、自分の IP アドレスをホワイトリストに追加する必要があります。そうしないと、取得できません。事前に「WeChat パブリック プラットフォーム - 開発 - 基本設定」にログインしてサーバー IP アドレスを IP ホワイトリストに追加してください。このマシンの IP は http://ip.qq.com/...で確認できます。
import 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)
を作成し、ユーザーに返します
写真を受信した後、顔検出を行ってアップロードするだけです。 Media_ID を取得するには、画像をユーザーに返すだけです。 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)
WeChat のメカニズムでは、プログラムは 5 秒以内に応答する必要があります。それ以外の場合は、「公式アカウントが提供するサービスに欠陥があります」と報告されます。ただし、画像処理が遅くなる場合があり、5 秒を超えることもよくあります。したがって、これを処理する正しい方法は、ユーザーのリクエストを受信した後、すぐに空の文字列を返して、それを受け取ったことを示し、画像を処理する別のスレッドを作成する必要があります。画像が処理されると、画像は に送信されます。カスタマーサービスインターフェースを通じてユーザーに伝えます。残念ながら、認証されていないパブリック アカウントにはカスタマー サービス インターフェイスがないため、5 秒以上かかるとエラーが報告されます。
カスタム開発を有効にすると、メニューもカスタマイズする必要があります。ただし、認定されていない公式アカウントにはプログラムを通じてメニューを構成する権限がなく、WeChat バックグラウンドでのみ構成できます。
ということで、私の公式アカウントではこのプログラムを有効にしていませんが、認定された公式アカウントをお持ちであれば、さまざまな楽しい機能の開発を試すことができます。
関連する推奨事項:
WeChat パブリック プラットフォーム開発 ワンクリックで WeChat パブリック プラットフォーム アカウントをフォロー
WeChat パブリック プラットフォーム開発の試み、WeChat パブリック プラットフォーム
ビデオ: Chuanzhi、Dark Horse WeChat パブリック プラットフォーム開発ビデオ チュートリアル
以上があなたがどれほど素敵か見てみましょう! Pythonをベースに開発されたパブリックアカウントの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。