从零开始制作H5人脸融合小游戏

去年的建军节,一个展示军装照的H5人脸融合游戏火遍朋友圈,带来很好的传播效果。最近欧冠决赛要来了,公司决定做一个寻找和你最像的欧冠球星的H5游戏,那么该怎么做呢?认真分析了一下,这个游戏其实用到的技术还是挺多的,是一个比较综合的项目。主要用到技术如下:

人脸识别
Python web和Java web
域名解析和nginx
微信JS
H5页面

人脸识别

人脸识别的API各大平台都有提供,百度,阿里,优图(腾讯),Face++. 各家的API大体相似,主要区别只是取的点的个数和返回结果的数据结构,都可用。BAT的都有免费可用(如果对QPS没有过高要求的话),Face++ 需要收费1元/次(墙裂怀疑失了智)。综合比较之后选择使用优图。
http://open.youtu.qq.com/#/develop/api-face-analysis-detect
SDK下载
http://open.youtu.qq.com/#/develop/tool-sdk
后端采用python,所以下载python版本的SDK。

youtu配置

从优图获取的人脸识别之后的信息全部是面部点的信息,需要进行处理,具体的处理方法全部在
https://github.com/tonyiweb/face_merge_master (star,fork来一套?)
感兴趣的star,fork一下

人脸融合大师,可以满足你10分钟做出人脸融合功能的理想工具,你值得拥有。

Python web和Java web

基于性能和表现的考虑,做了一个分离。图片识别和融合的功能全部放在一个Python web项目中,作为一个api,然后在Java web项目中调用这个API,将返回的结果或者错误信息返回到H5页面。

Python web

python是一个能快速开发的语言,有很多易用的web框架可以使用,这里就选择Tornado这个框架。


Tornado使用

服务器上通过nohup python -u run.py& 就可以启动一个端口号为9010(代码中可以指定,一般在7000以后)的服务。 nohup可以保证服务长期后台运行,并且可以通过tail -f nohup.out来查看日志。服务可以通过ps -ef|grep python查询服务的pid,再通过kill -9 pid来停止。

Java web

采用SpringBoot搭建的微服务,没有任何界面。接受H5页面传过来的图片,去调用人脸融合的API,根据结果返回调用结果或者错误信息。


API返回结果

域名解析和nginx

域名解析的过程其实就是一个通过名字(相对好记一些)找IP地址(相对难以记忆)的过程,而IP地址又对应一台服务器,也就是通过名字定位服务器。在控制台的域名解析中新加一条记录,指向代码部署的服务器。
因为一台服务器上其实是部署多个服务,也会被多个域名所指向,所以其实还需要一个东西来指引服务所要对应的域名,这个东西就是nginx。 一个服务一般是要对应一个端口的,nginx可以监听一个端口,然后将这个端口的服务定向到某个域名。


仅支持https

既支持http也支持https

注意:1,https服务需要安全证书,可以在阿里云的安全中的CA证书服务中购买(有免费的Symantic的证书)
2,一般默认的是http的,如果没有必要可以不用带安全证书的https服务
3,通过whereis nginx命令查找nginx的位置,通过vhost统一管理nginx配置文件
4,配置完nginx之后,需要重启nginx服务,命令: ./nginx -s reload 如果没有错误,就说明已经重启了。

微信JS

因为网页是放在微信环境下传播的,需要使用到微信的一些基础功能,如拍照,所以使用微信的JS SDK.
参考文档:https://www.w3cschool.cn/weixinkaifawendang/h8ap1qe5.html

1,配置微信。需要在后台根据jsapi_ticket等信息生成签名

(1)前台

//这里的url为当前页面的路径,为了使得分享之后的链接也是可用
var url = window.location.href;
$.get(baseUrl+"/common/get_wx_config",{url:url},
  function(data){
  wx.config({
        debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
        appId: data.appId,   // 必填,公众号的唯一标识
        timestamp: data.timestamp, // 必填,生成签名的时间戳
        nonceStr: data.nonceStr, // 必填,生成签名的随机串
        signature: data.signature,// 必填,签名,
        jsApiList: ['checkJsApi','chooseImage','uploadImage','onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareQZone'] // 必填,需要使用的JS接口列表
    });
    setShareInfo('','');
  })

(2)后台,微信签名过程


微信签名过程

2,拍照或者从相册中选择照片

var serverId='0';
function getPic(){
    wx.checkJsApi({
        jsApiList: ['chooseImage'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
        success: function(res) {
            if(res.checkResult.chooseImage){
                wx.chooseImage({
                    count: 1, // 默认9
                    sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
                    sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
                    success: function (res) {
                        var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
                        $("#selfImg").attr("src",localIds);
                        wx.uploadImage({
                            localId: localIds[0], // 需要上传的图片的本地ID,由chooseImage接口获得
                            isShowProgressTips: 1, // 默认为1,显示进度提示
                            success: function (res) {
                                serverId = res.serverId; // 返回图片的服务器端ID
                                $("#nextBtn").css("display","block");
                            }
                        });
                    }
                });
            }else{
                showAlert("微信版本过低,无法使用相机和相册功能","fail");
            }
        }
    });
}

3,上传图片并获得人脸融合结果

(1)前台

if(serverId!='0'){
        if(gender==1){
            showAlert("正在玩命给小主儿寻找最像你的球星...","loading");
        }else{
            showAlert("正在玩命给小主儿寻找最像你的球星太太...","loading");
        }
        //在服务器端下载图片,并作人脸融合,返回融合后的结果给img的src
        $.get(baseUrl+"/common/download_image",{serverId:serverId,gender:gender},
            function(data){
            if(data.status=='success'){
                hideAlert();
                $("#loadingPage").css("display","none");
                $("#firstPage").css("display","none");
                $("#secondPage").css("display","none");
                $("#thirdPage").css("display","block");
                var imageData = JSON.parse(data.data);
                $("#resultName").html(imageData.modelShortName);
                if(gender==1){
                    $("#discriptionText").html(imageData.description+',要被你迷倒啦(^_-');
                    setShareInfo(imageData.imageUrl[2],'和我最像的欧冠球星是'+imageData.modelShortName+','+imageData.description)
                }else{
                    $("#discriptionText").html(imageData.modelName+','+imageData.description+',要被你迷倒啦(^_-');
                    setShareInfo(imageData.imageUrl[2],'和我最像的欧冠女神是'+imageData.modelShortName+','+imageData.description)
                }

                $('#firstResultImg').animateCss('fadeIn', function() {
                    $("#firstResultImg").attr("src",imageData.imageUrl[0]);
                    $("#firstResultImg").addClass('animated flash');
                    $("#secondResultImg").animateCss('fadeIn',function(){
                        $("#secondResultImg").attr("src",imageData.imageUrl[1]);
                        $("#secondResultImg").addClass('animated flash');
                        $("#thirdResultImg").animateCss('fadeIn',function(){
                            $("#thirdResultImg").attr("src",imageData.imageUrl[2]);
                            $("#thirdResultImg").addClass('animated flash');
                            $("#fourthResultImg").animateCss('fadeIn',function(){
                                $("#fourthResultImg").attr("src",imageData.imageUrl[3]);
                                $("#fourthResultImg").addClass('animated flash');
                                $("#resultName").addClass('animated bounceIn');
                            });
                        });
                    });
                });
            }else{
                if(gender==1){
                    showAlert("好遗憾,没有找到和你相像的球星呢...换张照片,再玩一次吧","fail");
                }else{
                    showAlert("好遗憾,没有找到和你相像的球星太太呢...换张照片,再玩一次吧","fail");
                }
            }
        })
    }else{
        showAlert("好遗憾,你还没有上传任何照片哦...","fail");
    }

(2)后台,上传照片并进行人脸融合


上传照片并进行人脸融合

注意:需要在真机上才可以调用相机和相册
注意:要使用的域名必须在公众号设置——>功能设置中添加

H5页面

页面的大半是要依赖UI设计师,下面放些设计图,实现过程就省略掉(假装不重要.)...

启动页

性别选择页

上传照片页

结果页

后面是制作完成后得到页面(请在微信中打开): https://worldcup.superwr.top/index.html
另外还有世界杯的改进版(加入了生成海报图片和负载均衡):https://worldcup.pro365.cn/index.html

注意:H5页面的难点其实是在于兼容,这里通过计算设备宽度,得到相对尺寸rem,然后给元素设置以rem为单位的位置尺寸等信息,做到全部兼容ios移动设备和大部分Android设备
注意:页面中使用到了Animate.css这个CSS动画框架,链接:http://blog.superwr.top/2018/%E5%8A%A8%E7%94%BB%E6%8F%92%E4%BB%B6animate-css%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E/

欢迎访问个人博客:http://blog.superwr.top/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,651评论 18 139
  • 第一章 Nginx简介 Nginx是什么 没有听过Nginx?那么一定听过它的“同行”Apache吧!Ngi...
    JokerW阅读 32,670评论 24 1,002
  • 与猫有关的日子(一)之蛋黄 最早认识猫是我小时候在辽宁见的。 那边的天气很冷,印象中父母那时养了很多的...
    一只随遇而安的猫阅读 279评论 0 0
  • 项目要做一个摇一摇抽奖的需求,于是就提前做了个简化的Demo,遇到的坑啊什么的,当然是记录下来啦~~摇一摇抽奖的大...
    莦婼姑娘阅读 2,048评论 0 4
  • 今天,圣诞节,我跟同学作为一名预备党员去参加了预备党员培训,经过昨天一天思想的洗礼,今天准备继续聆听时,老师让...
    慵懒小书虫阅读 1,887评论 13 91