备战双十一·谁的表情包在天上飞

文章概要

前言
双十一刚过,这个全民吃土的时期,闲鱼非常贴心的推出了一个土味表情包的活动,可以通过定制表情包来吐槽并分享大家吃土的心声,这篇文章将为大家介绍如何用Python和weex快速搭建这样一个基于人脸识别的活动项目。

关键词:weex、Python、人脸识别

  1. 前端搭建
    前端页面主要包括:拍照和生成表情两部分。

1.1 拍照
拍照使用的是windvane的拍照模块,目前只能支持weex环境,h5环境暂时只能通过提示和拉端让引导用户到闲鱼or手淘去生成土味表情。在手淘的最新版本8.1.0中,直接用WVCamera.takePhoto进行拍照和上传图片可能出现问题,所以需要把拍照和上传图片分开调用,上传图片使用WVCamera.confirmUploadPhoto接口。

var

params
= {

type: 

‘0’
,

};

window.
WindVane
.call(
‘WVCamera’
,
‘takePhoto’
,
params
,
function
(e) {

var
uploadParams = {

// 需要上传的照片的路径

    path: e.localPath,

// 上传方式

    v: 

‘2.0’
,

// 业务代码

    bizCode: 

‘mtopupload’

};

setTimeout(

function
() {

    window.

WindVane
.call(
‘WVCamera’
,
‘confirmUploadPhoto’
, uploadParams,
function
(e) {

        alert(

'upload success: ’

  • JSON.stringify(e));

     }, 
    

function
(e) {

        alert(

'upload failure: ’

  • JSON.stringify(e));

     });
    

    },
    20
    );

},
function
(e) {

alert(

'takePhoto failure: ’

  • JSON.stringify(e));

});

1.2 生成表情
通过调用后台接口,传人照片地址和表情模板编号,生产表情后,接口会返回表情的地址然后渲染。
效果如下

  1. 服务端搭建

工程服务端使用纯Python搭建,可以满足快速搭建并部署上线活动的需求,使用的是SocketServer、BaseHTTPServer这两个库构建出的Http服务器:

socketserver是标准库中的一个高级模块,用于网络客户端与服务器的实现。模块中,已经实现了一些可供使用的类,socketserver模块包括许多可以简化TCP,UDP,UNIX域套接字服务器实现的类;

BaseHTTPServer模块构造了HTTP请求处理基类BaseHTTPRequestHandler,它继承自SocketServer模块中的StreamRequestHandler类;

用起来很方便,调用如下:

import

BaseHTTPServer

as
webservice

from

SocketServer

import

ThreadingMixIn

from

BaseHTTPServer

import

HTTPServer
,
BaseHTTPRequestHandler

if
name ==
main
:

serverAddress = (

‘’
, PORT)

server = 

ThreadingHttpServer
(serverAddress,
RequestHandler
)

server.serve_forever()

当有http请求,会触发RequestHandler的do_GET回调,执行里面的业务代码

class

RequestHandler
(webservice.
BaseHTTPRequestHandler
):

def
do_GET(
self
):

基础的调用实现之后,接下来的工作还有用ThreadingHttpServer来实现多线程的webserver,对参数做签名校验,使用Nginx来做分流等…就不一一细说了。

  1. 算法选型
    人脸融合到表情包的过程可以分四步:

人脸检测

人脸位置对齐

提取脸部五官特征,合成到表情包

调节脸的色调

3.1 在人脸识别部分,我们使用的是dlib库,可以很方便快捷的识别出脸部的68个点,点位置的分布如图:

使用起来很简单:

初始化dlib

detector = dlib.get_frontal_face_detector()

predictor = dlib.shape_predictor(PREDICTOR_PATH)

获取脸部特征点

def
get_landmarks(im):

rects = detector(im, 

1
)

if
len(rects) >
1
:

raise

TooManyFaces

if
len(rects) ==
0
:

raise

NoFaces

return
numpy.matrix([[p.x, p.y]
for
p
in
predictor(im, rects[
0
]).parts()])

3.2 人脸位置对齐,我们取到两张脸的标记矩阵之后,通过使用奇异值分解计算旋转,再利用仿射变换矩阵转化:

def
warp_im(im, M, dshape):

output_im = numpy.zeros(dshape, dtype=im.dtype)

cv2.warpAffine(im,

               M[:

2
],

               (dshape[

1
], dshape[
0
]),

               dst=output_im,

               borderMode=cv2.BORDER_TRANSPARENT,

               flags=cv2.WARP_INVERSE_MAP)

return
output_im

3.3 提取人脸中间特征包括了眼睛、眉毛、鼻子、嘴巴,将这个T字型的关键区域,需要将特征连接成一个凸多边形,然后使用cv.fillConvexPoly填充生成mask遮罩,遮罩的边缘外部羽化扩展,隐藏不连续区域,而表情包的底图需要先将原有的表情擦除,防止原有特征影响照片的图案,再将遮罩与表情包底图的脸部特征矩阵对齐,得到混合图案。

3.4 调节脸的色调是最后一步,经过上一步合成的脸还是原来的色值,需要转换为黑白的图片,首先去色,然后使用gamma曲线调节对比度,让脸部黑色部分更黑,白色部分更白,特征更加明显,调节对比度方法如下:

传入参数越大对比度越高

def
gamma_trans(img,gamma):

gamma_table = [numpy.power(x/

255.0
,gamma)*
255.0

for
x
in
range(
256
)]

gamma_table = numpy.round(numpy.array(gamma_table)).astype(numpy.uint8)

return
cv2.LUT(img,gamma_table)

  1. 算法优化
    我们从两个方面对算法做了简单的优化:

一是使用多进程优化,这步使用的是loky库实现:

import
loky

from
loky
import
get_reusable_executor

执行部分:

work_thread为机器能使用的最大进程数

executor = get_reusable_executor(max_workers=work_thread, timeout=

60
)

params
= []

传入需要多进程执行的方法名和参数,多个参数需要合成一个传入

result = executor.map(do_func, 

params
)

try
:

while

1
:

        re = result.

next
()

需要注意的是dlib的初始化部分,需要放入多进程优化的函数中,如果作为单例,dlib库会报no safe错误,而当dlib初始化放到了多进程的函数中,每次初始化都会调用一遍,这也是一个耗时的点,使用时需要去权衡优化。

另外还有一点需要注意是,如果你的功能是用Python2实现,另一个更加主流方便的多进程库Process则不能使用,与dlib会有冲突。

二是压缩检测区域,可以对原图先复制一个副本然后将副本压缩至1/4,然后传入dlib中进行识别,再对识别出的landmarks特征数组乘以4,得到原来的特征位置,再来处理原图和复原后的特征点集。除了压缩还可以通过裁剪来减小dlib的计算量,截取ROI区域,识别时将表情包人脸的区域截取出来传入dlib,聚焦图片中部位置识别,或者可以配合OpenCV的背景去除来缩小识别区域。

总结
以上就是表情包活动的全部实现流程了,其中性能、效果还有很多可以优化的点,欢迎大家在闲鱼或者手淘体验”拯救吃土族“定制表情包并提出建议和反馈~

原文链接

https://mp.weixin.qq.com/s?__biz=MzU4MDUxOTI5NA%3D%3D&mid=2247484119&idx=1&sn=0dee8431fa8781dde30291e9effdb812&chksm=fd54d6c6ca235fd0a804fb09d246d97333b96ffbd971bd804e8d483307e52be952762243223c&mpshare=1&scene=23&srcid=%23rd

服务推荐

猜你喜欢

转载自blog.csdn.net/gt9000/article/details/85991848