摘要:上篇文章,我們把自己的程序接入了微信公眾號,并且能把用戶發(fā)送的文本及圖片文件原樣返回。微信的機(jī)制,我們的程序必須在內(nèi)給出響應(yīng)。上篇微信公眾號開發(fā)小白篇一
上篇文章,我們把自己的程序接入了微信公眾號,并且能把用戶發(fā)送的文本及圖片文件原樣返回。今天我們把用戶的圖片通過騰訊的AI平臺分析后再返回給用戶。
為了防止我的文章被到處轉(zhuǎn)載,貼一下我的公眾號【智能制造社區(qū)】,歡迎大家關(guān)注。
github倉庫地址https://github.com/injetlee/Python/tree/master/wechat
效果圖 一. 接入騰訊AI平臺我們先看一下官方人臉檢測與分析接口的描述:
檢測給定圖片(Image)中的所有人臉(Face)的位置和相應(yīng)的面部屬性。位置包括(x, y, w, h),面部屬性包括性別(gender), 年齡(age), 表情(expression), 魅力(beauty), 眼鏡(glass)和姿態(tài)(pitch,roll,yaw)。
請求參數(shù)包括下面幾個(gè):
app_id 應(yīng)用標(biāo)識,我們在AI平臺注冊后就可以得到app_id
time_stamp 時(shí)間戳
nonce_str 隨機(jī)字符串
sign 簽名信息,需要我們自己去計(jì)算
image 需要檢測的圖片(上限1M)
mode 檢測模式
1.接口鑒權(quán),構(gòu)造請求參數(shù)官方給了我們接口鑒權(quán)的計(jì)算方法。
將
將列表N中的參數(shù)對按URL鍵值對的格式拼接成字符串,得到字符串T(如:key1=value1&key2=value2),URL鍵值拼接過程value部分需要URL編碼,URL編碼算法用大寫字母,例如%E8,而不是小寫%e8
將應(yīng)用密鑰以app_key為鍵名,組成URL鍵值拼接到字符串T末尾,得到字符串S(如:key1=value1&key2=value2&app_key=密鑰)
對字符串S進(jìn)行MD5運(yùn)算,將得到的MD5值所有字符轉(zhuǎn)換成大寫,得到接口請求簽名
2.請求接口地址請求接口信息,我們用 requests 發(fā)送請求,會得到返回的 json 格式的圖像信息pip install requests安裝requests。
3.處理返回的信息處理返回的信息,把信息展示在圖片上,再把處理后的圖片保存。這里我們用到 opencv ,和 pillow 兩個(gè)庫pip install pillow和pip install opencv-python來安裝。
開始編寫代碼,我們新建一個(gè)face_id.py 文件來對接AI平臺,并且返回檢測后的圖像數(shù)據(jù)。
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 # 一.計(jì)算接口鑒權(quán),構(gòu)造請求參數(shù) def random_str(): """得到隨機(jī)字符串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): """組織接口請求的參數(shù)形式,并且計(jì)算sign接口鑒權(quán)信息, 最終返回接口請求所需要的參數(shù)字典""" 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() # 計(jì)算出sign,接口鑒權(quán) params["sign"] = md5text # 添加到請求參數(shù)列表中 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) # 圖片轉(zhuǎn)為base64編碼格式 url = "https://api.ai.qq.com/fcgi-bin/face/face_detectface" res = requests.post(url, get_params(img_encode)).json() # 請求URL,得到j(luò)son信息 # 把信息顯示到圖片上 if res["ret"] == 0: # 0代表請求成功 pil_img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # 把opencv格式轉(zhuǎn)換為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坐標(biāo) y = obj["y"] # 人臉框左上角y坐標(biāo) w = obj["width"] # 人臉框?qū)挾? h = obj["height"] # 人臉框高度 # 根據(jù)返回的值,自定義一下顯示的文字內(nèi)容 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: # 檢測到多個(gè)人臉,就把信息寫入人臉框內(nèi) 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: # 避免圖片太窄,導(dǎo)致文字顯示不完全 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 格式轉(zhuǎn)換為 cv cv2.imwrite("faces/{}".format(os.path.basename(img)), cv2img) # 保存圖片到 face 文件夾下 return "檢測成功" else: return "檢測失敗"
到這里我們的人臉檢測接口接入及圖片處理就完成了。之后在收到用戶發(fā)送的圖片信息后,調(diào)用這個(gè)函數(shù),把處理后的圖片返回給用戶就可以。
返回圖片給用戶當(dāng)收到用戶圖片時(shí),需要以下幾個(gè)步驟:
保存圖片當(dāng)接收到用戶圖片后,我們要先把圖片保存起來,之后才能去調(diào)用人臉分析接口,把圖片信息傳遞過去,我們需要編寫一個(gè) img_download 函數(shù)來下載圖片。詳見下方代碼
調(diào)用人臉分析接口圖片下載后,調(diào)用 face_id.py 文件里的接口函數(shù),得到處理后的圖片。
上傳圖片檢測結(jié)果是一張新的圖片,要把圖片發(fā)送給用戶我們需要一個(gè) Media_ID,要獲取Media_ID必須先把圖片上傳為臨時(shí)素材,所以這里我們需要一個(gè)img_upload函數(shù)來上傳圖片,并且在上傳時(shí)需要用到一個(gè)access_token,我們通過一個(gè)函數(shù)來獲取. 獲取access_token必須要把我們自己的IP地址加入白名單,否則是獲取不到的。請登錄“微信公眾平臺-開發(fā)-基本配置”提前將服務(wù)器IP地址添加到IP白名單中,可以在http://ip.qq.com/查看本機(jī)的IP...
開始編寫代碼,我們新建一個(gè) utils.py 來下載、上傳圖片
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)返回給用戶
我們簡單修改下收到圖片后的邏輯,收到圖片后經(jīng)過人臉檢測,上傳獲得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)
至此我們的工作就做完了,我們的公眾號可以進(jìn)行顏值檢測了。本來我打算用在自己公眾號上的,但是還存在下面幾個(gè)問題,所以沒有使用。
微信的機(jī)制,我們的程序必須在5s內(nèi)給出響應(yīng)。不然就會報(bào)"公眾號提供的服務(wù)出現(xiàn)故障"。然而處理圖片有時(shí)會比較慢,經(jīng)常會超過5s。所以正確的處理方式應(yīng)該是拿到用戶的請求后立即返回一個(gè)空字符串表示我們收到了,之后多帶帶創(chuàng)建一個(gè)線程去處理圖片,當(dāng)圖片處理完后通過客服接口發(fā)送給用戶??上У氖俏凑J(rèn)證的公眾號沒有客服接口,所以沒辦法,超過5s就會報(bào)錯(cuò)。
無法自定義菜單,一旦啟用了自定義開發(fā),菜單也需要自定義配置,但是未認(rèn)證的公眾號沒有權(quán)限通過程序來配置菜單,只能在微信后臺配置。
所以,我并沒有在我的公眾號上啟用這個(gè)程序,但是如果有認(rèn)證的公眾號,可以嘗試開發(fā)各種好玩的功能。
上篇:Python微信公眾號開發(fā)—小白篇(一)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/41864.html
摘要:上篇文章,我們把自己的程序接入了微信公眾號,并且能把用戶發(fā)送的文本及圖片文件原樣返回。微信的機(jī)制,我們的程序必須在內(nèi)給出響應(yīng)。上篇微信公眾號開發(fā)小白篇一 上篇文章,我們把自己的程序接入了微信公眾號,并且能把用戶發(fā)送的文本及圖片文件原樣返回。今天我們把用戶的圖片通過騰訊的AI平臺分析后再返回給用戶。 為了防止我的文章被到處轉(zhuǎn)載,貼一下我的公眾號【智能制造社區(qū)】,歡迎大家關(guān)注。 githu...
摘要:作者微信公眾號的皮卡丘歡迎大家搜索關(guān)注知乎機(jī)器學(xué)習(xí)美顏簡單品讀小說實(shí)現(xiàn)顏值預(yù)測預(yù)測比賽結(jié)果制作且版飛機(jī)大戰(zhàn)實(shí)現(xiàn)簡單的換臉術(shù)遺傳算法擬合圖像實(shí)現(xiàn)貓臉檢測分析個(gè)人音樂收藏垃圾郵件識別深度學(xué)習(xí)強(qiáng)化學(xué)習(xí)玩破解游戲?qū)崿F(xiàn)簡單的機(jī)器翻譯模型學(xué)寫作實(shí)現(xiàn)文本 作者:Charles微信公眾號:Charles的皮卡丘(歡迎大家搜索關(guān)注)知乎:https://zhuanlan.zhihu.com/p/... ...
摘要:時(shí)間永遠(yuǎn)都過得那么快,一晃從年注冊,到現(xiàn)在已經(jīng)過去了年那些被我藏在收藏夾吃灰的文章,已經(jīng)太多了,是時(shí)候把他們整理一下了。那是因?yàn)槭詹貖A太亂,橡皮擦給設(shè)置私密了,不收拾不好看呀。 ...
摘要:可以說是每個(gè)程序每天必逛的網(wǎng)站,這里集聚了全球最頂級的程序員。有非常多的大公司在上面開源自己的項(xiàng)目。今天整理了個(gè)上頂級的開源項(xiàng)目。這是推出的一款性能類型檢查工具。它的主要目標(biāo)是快速輕松地分發(fā)應(yīng)用程序。 showImg(https://segmentfault.com/img/remote/1460000015909645); 閱讀文本大概需要 4.2 分鐘。 GitHub 可以說是每個(gè)...
閱讀 3286·2021-11-24 09:38
閱讀 2158·2021-11-23 09:51
閱讀 1750·2021-10-13 09:39
閱讀 2624·2021-09-23 11:53
閱讀 1408·2021-09-02 15:40
閱讀 3660·2019-08-30 15:54
閱讀 1135·2019-08-30 13:04
閱讀 2566·2019-08-30 11:01