> 위챗 애플릿 > 위챗 개발 > 얼마나 잘 생겼는지 볼까요! Python 기반으로 개발된 공개 계정

얼마나 잘 생겼는지 볼까요! Python 기반으로 개발된 공개 계정

php是最好的语言
풀어 주다: 2018-07-25 13:56:17
원래의
2477명이 탐색했습니다.

모습 감지를 위한 Python 기반 WeChat 공개 계정 개발입니다. 오늘은 Tencent의 AI 플랫폼을 통해 사용자의 사진을 분석한 후 사용자에게 반환합니다. 공개 계정의 액면가 감지를 함께 경험해 보세요

Rendering

얼마나 잘 생겼는지 볼까요! Python 기반으로 개발된 공개 계정

얼마나 잘 생겼는지 볼까요! Python 기반으로 개발된 공개 계정

얼마나 잘 생겼는지 볼까요! Python 기반으로 개발된 공개 계정

1. Tencent AI 플랫폼에 연결

먼저 공식 얼굴 감지 및 분석 인터페이스에 대한 설명을 살펴보겠습니다.

주어진 이미지에 있는 모든 얼굴의 위치와 해당 얼굴 특성을 감지합니다. 위치에는 (x, y, w, h)가 포함되며 얼굴 속성에는 성별, 나이, 표정, 아름다움, 안경 및 자세(피치, 롤, 요)가 포함됩니다.

요청 매개변수에는 다음이 포함됩니다.

  • app_id 애플리케이션 식별, AI 플랫폼

  • time_stamp 타임스탬프

  • nonce_str 무작위 문자열

  • 서명 정보에 등록한 후 app_id를 얻을 수 있습니다. , 우리가 직접 계산해야 합니다

  • 감지할 이미지 이미지(상한 1M)

  • 모드 감지 모드

1. 인터페이스 인증, 요청 매개변수 구성

공식에서 계산 방법을 알려줬습니다. 인터페이스 인증.

  1. 요청 매개변수 쌍을 키별로 사전 오름차순으로 정렬하여 정렬된 매개변수 쌍 목록을 얻습니다. N

  2. 목록 N의 매개변수 쌍을 URL 형식에 따라 문자로 연결합니다. 키-값 쌍 문자열을 사용하여 문자열 T(예: key1=value1&key2=value2)를 얻습니다. URL 키-값 접합 프로세스의 값 부분에는 URL 인코딩 알고리즘이 대신 %E8과 같은 대문자를 사용합니다. 소문자 %e8

  3. 애플리케이션 비밀번호는 다음과 같습니다. 키는 app_key를 키 이름으로 사용하고 URL 키 값은 문자열 T의 끝에 연결되어 문자열 S를 얻습니다(예: key1=value1&key2 =value2&app_key=key)

  4. 문자열 S에 대해 MD5 연산을 수행하고 MD5를 얻습니다. 값의 모든 문자를 대문자로 변환하고 인터페이스 요청 서명을 얻습니다.

2. 인터페이스를 요청하려면 인터페이스 주소

를 요청하세요. 우리는 요청을 전송하기 위해 요청을 사용하며, pip install requestsInstall Requests) 형식으로 반환된 이미지 정보를 받게 됩니다. pip install requests安装requests。

3.处理返回的信息

处理返回的信息,把信息展示在图片上,再把处理后的图片保存。这里我们用到 opencv ,和 pillow 两个库pip install pillowpip install opencv-python

3. 반환된 정보를 처리합니다

반환된 정보를 처리하고 사진에 정보를 표시한 후 처리된 사진을 저장합니다. 여기서는 설치를 위해 opencv 및 Pillow 라이브러리 pip install Pillowpip 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[&#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;
로그인 후 복사

이 시점에서 얼굴 인식 인터페이스 액세스 및 이미지 처리가 완료되었습니다. 사용자가 보낸 사진 정보를 받은 후 이 함수를 호출하여 처리된 사진을 사용자에게 반환합니다.

사용자에게 이미지를 반환합니다

사용자 이미지를 수신할 때 다음 단계가 필요합니다.

이미지 저장

사용자 이미지를 수신한 후 얼굴 분석 인터페이스를 호출하기 전에 먼저 이미지를 저장해야 합니다. 이미지 정보를 얻으려면 img_download 함수를 작성하여 이미지를 다운로드해야 합니다. 자세한 내용은 아래 코드를 참고하세요

얼굴 분석 인터페이스 호출

이미지 다운로드 후, faces_id.py 파일에 있는 인터페이스 함수를 호출해 처리된 이미지를 가져옵니다.

사진 업로드

감지 결과는 새로운 사진입니다. 사진을 사용자에게 보내려면 Media_ID를 얻으려면 먼저 사진을 임시 자료로 업로드해야 하므로 여기서는 img_upload 함수가 필요합니다. 사진을 업로드하려면 access_token이 필요하며, 우리는 함수를 통해 그것을 얻습니다.

access_token을 얻으려면 우리 자신의 IP 주소를 화이트리스트에 추가해야 합니다. 그렇지 않으면 우리는 그것을 얻을 수 없습니다. "WeChat 공개 플랫폼 - 개발 - 기본 구성"에 로그인하여 서버 IP 주소를 IP 화이트리스트에 미리 추가하세요. http://ip.qq.com/...

에서 이 컴퓨터의 IP를 볼 수 있습니다.

코드 작성을 시작하고 사진을 다운로드하고 업로드하기 위한 새로운 utils.py를 생성합니다.

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)
로그인 후 복사

그리고 이를 사용자에게 반환합니다.

사진을 받은 후 로직을 수정하면 얼굴 감지 및 업로드가 수행됩니다. 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(&#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)
로그인 후 복사
🎜의 코드를 직접 살펴보세요. 이제 작업이 완료되었으며 공식 계정의 모양을 테스트할 수 있습니다. 원래는 공식 계정에서 사용하려고 했으나, 아직 문제가 많아서 사용하지 못했습니다. 🎜
  1. WeChat의 메커니즘을 사용하면 우리 프로그램은 5초 이내에 응답해야 합니다. 그렇지 않으면 '공식 계정에서 제공하는 서비스에 결함이 있습니다'라고 보고됩니다. 그러나 이미지 처리가 때로는 느려서 5초를 초과하는 경우도 있습니다. 따라서 이를 처리하는 올바른 방법은 사용자의 요청을 받은 후 즉시 빈 문자열을 반환하여 이를 수신했음을 표시한 다음 이미지를 처리할 별도의 스레드를 생성하여 이미지를 처리하는 것입니다. 고객 서비스 인터페이스를 통해 사용자. 아쉽게도 인증되지 않은 공개 계정은 고객 서비스 인터페이스가 없기 때문에 5초 이상 소요될 경우 오류가 발생합니다.

  2. 메뉴를 사용자 정의할 수 없습니다. 사용자 정의 개발이 활성화되면 메뉴도 사용자 정의해야 합니다. 그러나 인증되지 않은 공식 계정은 프로그램을 통해 메뉴를 구성할 수 있는 권한이 없으며 WeChat 백그라운드에서만 구성할 수 있습니다.

그래서 공식 계정에서는 이 프로그램을 활성화하지 않았지만, 인증된 공식 계정이 있다면 다양하고 재미있는 기능을 개발해 볼 수 있습니다.

관련 추천:

WeChat 공개 플랫폼 개발 원클릭 WeChat 공개 플랫폼 계정 팔로우

WeChat 공개 플랫폼 개발 시도, WeChat 공개 플랫폼

동영상: Chuanzhi, Dark Horse WeChat 공개 플랫폼 개발 동영상 튜토리얼

위 내용은 얼마나 잘 생겼는지 볼까요! Python 기반으로 개발된 공개 계정의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿