打印

连载:将人脸识别微服务化,容器化【原创】

[复制链接]
2062|9
跳转到指定楼层
楼主
本帖最后由 keer_zu 于 2019-3-1 15:48 编辑

@21ic小喇叭 @21ic小管家 @gaoyang9992006 @sherwin @海中水 @tyw @yyy71cj @紫剑

广告:欢乐赛车最近在抽空学《微分几何》和《群论》

将人脸识别应用微服务化,进一步容器化是我当下的任务。
可以实现类似科大讯飞的云服务器一样的人脸识别服务,这一切从定义接口开始。
要定义接口,首先是选择通信方式:tcp or http。


代码依然参考:

tcp效率高,交互方式灵活。但是因为进出服务器都有传输图片或者流的可能,所以tcp实现的接口很不友好,对接入者要求过高。先从两者对比开始吧。
首先是尝试采用tcp传输图片:

  1. import socket
  2. import threading

  3. import time
  4. import sys
  5. import os
  6. import struct


  7. class _Session:
  8.     m_conn = 0
  9.     m_addr = 0
  10.     m_tread = 0

  11.     def __init__(self,conn,addr,on_session):
  12.         self.m_conn = conn
  13.         self.m_addr = addr

  14.         self.m_tread = threading.Thread(target=on_session, args=(conn, addr))
  15.         self.m_tread.start()


  16. class TcpServer:

  17.     def __init__(self,ip,port):
  18.         try:
  19.             s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  20.             s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  21.             s.bind((ip, port))
  22.             s.listen(10)
  23.         except socket.error as msg:
  24.             print(msg)
  25.             sys.exit(1)
  26.         print('Waiting connection...')

  27.         while 1:
  28.             conn, addr = s.accept()
  29.             #t = threading.Thread(target=deal_data, args=(conn, addr))
  30.             #t.start()
  31.             session = _Session(conn,addr,self.recv_image)


  32.     def recv_image(self,conn, addr):
  33.         print ('Accept new connection from {0}'.format(addr))
  34.         #conn.settimeout(500)
  35.         conn.send(('Hi, Welcome to the server!').encode())

  36.         while 1:
  37.             fileinfo_size = struct.calcsize('128sl')
  38.             buf = conn.recv(fileinfo_size)
  39.             if buf:
  40.                     filename, filesize = struct.unpack('128sl', buf)
  41.                     fn = filename.strip(('\00').encode())
  42.                     #src_path,_ = os.path.split(os.path.realpath(__file__))
  43.                     new_filename = os.path.join('./', 'new_' + fn.decode())
  44.                     print('file new name is {0}, filesize if {1}'.format(new_filename, filesize))
  45.                     recvd_size = 0 # 定义已接收文件的大小
  46.                     fp = open(new_filename, 'wb')
  47.                     print('start receiving...')

  48.                     while not recvd_size == filesize:
  49.                             if filesize - recvd_size > 1024:
  50.                                     data = conn.recv(1024)
  51.                                     recvd_size += len(data)
  52.                             else:
  53.                                     data = conn.recv(filesize - recvd_size)
  54.                                     recvd_size = filesize
  55.                             fp.write(data)
  56.                     fp.close()
  57.                     print('end receive...')
  58.             conn.close()
  59.             break

  60. class TcpClient:
  61.     def __init__(self,ip,port):
  62.         try:
  63.             s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  64.             s.connect((ip, port))
  65.         except socket.error as msg:
  66.             print(msg)
  67.             sys.exit(1)

  68.         print(s.recv(1024))

  69.         while 1:
  70.             filepath = input('please input file path: ')
  71.             if os.path.isfile(filepath):
  72.             # 定义定义文件信息。128s表示文件名为128bytes长,l表示一个int或log文件类型,在此为文件大小
  73.                 fileinfo_size = struct.calcsize('128sl')
  74.             # 定义文件头信息,包含文件名和文件大小
  75.                 fhead = struct.pack(('128sl').encode(), os.path.basename(filepath.encode()), os.stat(filepath).st_size)
  76.                 s.send(fhead)
  77.                 print('client filepath: {0}'.format(filepath))

  78.                 fp = open(filepath, 'rb')
  79.                 while 1:
  80.                     data = fp.read(1024)
  81.                     if not data:
  82.                         print('{0} file send over...'.format(filepath))
  83.                         break
  84.                     s.send(data)
  85.             s.close()
  86.             break

  87. tcp_server = TcpServer("127.0.0.1",6666)
  88. #tcp_client = TcpClient("127.0.0.1",6666)
复制代码


可以看到:首先是通过tcp传输图片名字和大小信息,然后才传输图片。

===============================================================================

接下来尝试采用http的post方法一次传输图片和命令。。。
先分享一种尝试:



=================================== 2019.2.22 =======================================

今天看了腾讯和百度的api定义:




感觉百度过于繁杂,还是比较喜欢腾讯的接口。于是着手学习之,自己实现类似接口。就从接口定义开始吧。

================================== 2019.2.26 =========================================
对比了若干个python的http框架,最好决定使用flask来实现我的http接口。
新的代码:


首先定义接口,然后一个一个实现。
接口定义详情请参考下面帖子。

第一个接口的实现请参考下面对应帖子。



==================================== 2019.3.1 =============================================

这两天致力于将之前python做的http服务容器化。

问题是这样的:首先,tensorflow的hub.docker.com
只有在具备nvidia显卡的机器上才能运行python3的环境,而且虚拟机不支持对显卡的虚拟化,所以必须在一台机器上安装nvidia的显卡,
然后运行linux系统(我是centos),接着docker pull 拉取 上面的镜像,再将其运行为支持nvidia环境的容器。

在centos上安装nvidia显卡颇费周折,因为是找来的旧显卡,而且我的显示器有比较古董,所以启动安装好的linux后就显示没有信号,找了很多解决办法,最后、
在nvidia的论坛得知新的显示器可以支持,无奈在公司地位卑微,用的都是淘汰的设备,于是斗胆接了一台新的三星显示器,可以显示。
按照别人试验过的方法,安装好驱动。再切换至之前的显示器,发现可以显示了。

于是拉取docker镜像,采用以下方式:
Start a GPU container with Python 3, using the Python interpreter.
  1. $ docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 tensorflow/tensorflow:latest-py3-jupyter
复制代码


OK! 容器跑起来了。
然后将我的faceclude代码用git克隆到共享文件夹中,又是一大波依赖包安装,终于跑起来了。
后边的开发就在容器里面做了。客户端demo(sdk)跑在其它地方,包括宿主机。

继续。

@gaoyang9992006 @sherwin @21ic小喇叭




评分

参与人数 1威望 +15 收起 理由
tyw + 15 很给力!
沙发
 楼主 | 2019-2-21 10:47 | 只看该作者
trans_http.py

  1. #!/usr/bin/python
  2. # -*-coding=utf-8 -*-

  3. import sys
  4. import traceback
  5. #from StringIO
  6. try:
  7.     from StringIO import StringIO
  8. except ImportError:
  9.         from io import StringIO
  10. import io
  11. import requests
  12. import tornado
  13. import tornado.ioloop
  14. import tornado.web
  15. from tornado.escape import json_encode
  16. from PIL import Image
  17. import imp


  18. imp.reload(sys)
  19. #sys.setdefaultencoding('utf8')

  20. class Handler(tornado.web.RequestHandler):
  21.     def post(self):
  22.         result = {}
  23.         image_url = self.get_argument("image_url", default="")
  24.         print (image_url)
  25.         if not image_url:
  26.             result["msg"] = "no image url"
  27.         else:
  28.             result["msg"] = self.process(image_url)

  29.         self.write(json_encode(result))
  30.     def process(self, image_url):
  31.         """
  32.         根据image_url获取图片进行处理
  33.         :param image_url: 图片url
  34.         """
  35.         try:
  36.             response = requests.get(image_url)
  37.             if response.status_code == requests.codes.ok:
  38.                 obj = Image.open(
  39.                         io.BytesIO(response.content))
  40.                 # TODO 根据obj进行相应的操作
  41.                 return "ok"
  42.             else:
  43.                 return "get image failed."
  44.         except Exception as e:
  45.             print (traceback.format_exc() )
  46.             return str(e)


  47. class ImageServer(object):
  48.     def __init__(self, port):
  49.         self.port = port
  50.     def process(self):
  51.         app = tornado.web.Application([(r"/image?", Handler)], )
  52.         app.listen(self.port)
  53.         tornado.ioloop.IOLoop.current().start()








  54. if __name__ == "__main__":
  55.     server_port = "6060"
  56.     server = ImageServer(server_port)
  57.     print ("begin server" )
  58. server.process()
复制代码
板凳
| 2019-2-21 13:39 | 只看该作者
地板
 楼主 | 2019-2-21 13:48 | 只看该作者
5
 楼主 | 2019-2-22 14:05 | 只看该作者
百度人脸检测概述:

  1. 人脸检测与属性分析

  2. 人脸识别接口分为V2和V3两个版本,本文档为V3版本接口的说明文档,请确认您在百度云后台获得的是V3版本接口权限,再来阅读本文档。

  3.     辨别接口版本的方法是:在百度云后台进入【应用列表】,点击【应用名称】,在【API列表】中可以看到【请求地址】,若请求地址中带有【v3】标识,则您具有的是v3权限,可以阅读本文档;若请求地址中带有【v2】标识,则您具有的是v2权限,应该去阅读v2文档。 如果您对文档内容有任何疑问,可以通过以下几种方式联系我们:

  4.     在百度云控制台内 提交工单,咨询问题类型请选择人工智能服务;
  5.     如有需要讨论的疑问,欢迎进入 AI社区 与其他开发者们一同交流。

  6. 能力介绍

  7. 接口能力

  8.     人脸检测:检测图片中的人脸并标记出位置信息;
  9.     人脸关键点:展示人脸的核心关键点信息,及150个关键点信息。
  10.     人脸属性值:展示人脸属性信息,如年龄、性别等。
  11.     人脸质量信息:返回人脸各部分的遮挡、光照、模糊、完整度、置信度等信息。

  12. 业务应用

  13. 典型应用场景:如人脸属性分析,基于人脸关键点的加工分析,人脸营销活动等。

  14.     说明:检测响应速度,与图片中人脸数量相关,人脸数量较多时响应时间会有些许延长。

  15. 质量检测

  16. 如果需要判断一张图片中的人脸,是否符合后续识别或者对比的条件,可以使用此接口,在请求时在face_field参数中请求quality。基于返回结果quality中,以下字段及对应阈值,进行质量检测的判断,以保证人脸质量符合后续业务操作要求。
复制代码
6
 楼主 | 2019-2-22 14:06 | 只看该作者
腾讯人脸验证概述:
  1. 1. 接口描述

  2. 接口请求域名: iai.tencentcloudapi.com 。

  3. 给定一张人脸图片和一个 PersonId,判断图片中的人和 PersonId 对应的人是否为同一人。PersonId 请参考人员库管理相关接口。 和人脸比对接口不同的是,人脸验证用于判断 “此人是否是此人”,“此人”的信息已存于人员库中,“此人”可能存在多张人脸图片;而人脸比对用于判断两张人脸的相似度。

  4. 默认接口请求频率限制:50次/秒。
复制代码
7
 楼主 | 2019-2-26 09:27 | 只看该作者
接口定义:




8
 楼主 | 2019-2-26 10:55 | 只看该作者



  1. import os
  2. from flask import Flask, request, redirect, url_for
  3. from werkzeug import secure_filename

  4. UPLOAD_FOLDER = '/root/src/test/img'
  5. ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])

  6. base_route = '/v1'

  7. app = Flask(__name__)
  8. app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
  9. def allowed_file(filename):
  10.     return '.' in filename and \
  11.            filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS




  12. # api: PersonnelDataEntry
  13. @app.route(base_route + '/PersonnelDataEntry', methods=['GET', 'POST'])
  14. def upload_file():
  15.     if request.method == 'POST':
  16.         print(request.args)
  17.         print(request.files)
  18.         file = request.files['file']
  19.         print(file.filename)
  20.         if file and allowed_file(file.filename):
  21.             filename = secure_filename(file.filename)
  22.             file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
  23.             return '''redirect(url_for('uploaded_file',
  24.                                     filename=filename))
  25.                                     '''
  26.     return '''
  27.     <!doctype html>
  28.     <title>Upload new File</title>
  29.     <h1>Upload new File</h1>
  30.     <form action="" method=post enctype=multipart/form-data>
  31.       <p><input type=file name=file>
  32.          <input type=submit value=Upload>
  33.     </form>
  34.     '''

  35. if __name__ == '__main__':
  36. app.run()
复制代码
9
| 2019-2-27 18:17 | 只看该作者
谢谢楼主分享
10
 楼主 | 2019-3-1 15:51 | 只看该作者
小地方做这些,其实什么都要自己弄,包括N次装系统。
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 投诉建议 创建版块 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

关闭

热门推荐上一条 /5 下一条

在线客服 快速回复 返回顶部 返回列表
美狮彩票 华阳彩票 128彩票 网易彩票 吉林快3计划 秒速赛车是真的吗 河北11选5走势图 美狮彩票 吉林快3计划 上海快3走势图