在TGC腾讯数字文创节,欢乐茶馆又开业了!此次茶馆在互动体验与运营上持续优化升级!
TGC2020 欢乐茶馆IP馆
《TGC2020.欢乐茶馆》正面图
TGC2020茶馆平面布局图:
TGC2020茶馆现场视频:
[##a3211c497br##]
TGC2020茶馆网络布局及大概内容规划:
欢乐检测机整套逻辑可走本地局域网设计方案,主要考虑:1、外网环境较差无法完成互动体验!2、局域网可忽略在性能优化与体验优化之间做平衡选择!
TGC2020茶馆主要互动模块:
1、欢乐检测机 ---包括:欢乐笑脸检测机+ 自助打印照片+大屏幕照片互动 + 小程序用户线上数据收集
2、欢乐麻将机--- 沉浸式麻将游戏体验
3、多媒体斗地主互动
4、舞台弹幕互动
5、舞台互动
6、IP周边打卡
7、积分兑换
为贴合2020TGC 数字化IP文化体验,欢乐茶馆经过几次迭代,在海南TGC已初步积累了一套互动体验方案。TGC茶馆场馆所有互动模块首次落地使用小程序打卡运营方式完成。方案在后期数据回顾,优化体验等方面都收到不错的反馈!
本文以TGC2020茶馆为例,重点介绍技术支持与思考,目录模块如下:
1、欢乐检测仪互动方案
2、欢乐麻将机互动方案
3、小程序场馆互动打卡解决方案
4、数据部分
----------------------------------------------------------------------------------------------------------------------
欢乐检测仪互动方案
互动内容概述:
- 玩家使用欢乐检测仪进行AI笑脸实时检测拍照,笑脸幅度不同自动匹配不同花色扑克牌(J\K\Q\A\2\W)
- 拍照结束后,生成3份模板照片(大屏幕笑脸照片(实时刷新)、小程序笑脸照片、扑克牌打印机打印照片)
- 玩家使用小程序扫码自动拉取玩家笑脸照片,点击关联保存,生成打印二维码
- 打印处,通过扫码枪自动识别小程序打印二维码,识别成功自动打印照片(打印照片拉取局域网照片)
互动流程图:
互动视频:(非现场终版)
[##r321157pbk0##]
互动主要功能:
- TensorFlow.js 技术实现 AI人脸表情识别 ,用于“笑脸实时识别匹配扑克牌”功能;
- 图片本地下载与上传云COS服务器功能;
- 小程序云开发:照片与用户信息绑定、照片打印状态管理;
- Node WS服务实现调用CMD命令自动连接打印机打印照片功能;
技术细节分析:
一、基于 TensorFlow.js 技术实现 AI人脸表情识别,生成对应对应扑克卡牌
TensorFlow简介
TensorFlow(以下简称为TF)是一个谷歌大脑团队开发的开源软件库,用于各种感知和语言理解任务的机器学习。
简单来说,就是你先通过精密的算法和大量的训练(训练模型),教会TF来做一些事情,它学会以后,就可以通过你之前的训练(加载模型),来完成一些复杂的操作或计算。
技术实现
回到项目本身,我们需求是用户在欢乐检测机上打开摄像头,根据摄像头拍摄到的人脸表情进行实时识别,如果画面中出现了笑脸,根据笑脸幅度不同自动匹配不同花色扑克牌(J\K\Q\A\2\W)
核心技术有两点:
- 获取摄像头的实时画面帧
- 将获取到的实时帧利用TFJS进行图像表情识别逻辑处理
实时帧:
打开摄像头视频流,使用实时绘制视频图片,同时绘制照片进行AI笑脸识别。
核心代码:
//打开视频流并实时绘制Canvas图片
async function videofun(videoState){
navigator.getUserMedia({
audio: true,
video: {
width: width,
height: height
}
},
function(stream) {
var video = document.querySelector('video');
video.srcObject = stream;
video.onloadedmetadata = function(e) {
//省略其他状态逻辑,必须添加,在非实时识别状态必须切换其他状态,避免电脑性能开销过高导致死机
if(videoState === 'faceonline'){
video.play();
videointerval = setInterval(drawCanvasImage, 0)
}
};
},
function(err) {
alert("摄像头视频流出错了: " + err.name);
}
);
}
//绘制Canvas图片函数
async function canvasimg(ratio) {
const canvas = document.getElementById('mycanvas');
canvas.width = width;
canvas.height = height;
const context = canvas.getContext('2d');
context.translate(canvas.width, 0); //照片镜像处理
context.scale(-1, 1) //照片镜像处理
context.drawImage(video, 0, 0, width, height, 0, 0, canvas.width, canvas.height);
const imageData = canvas.toDataURL("image/jpeg",ratio);
return imageData;
}
//实时视频流绘制canvas图片并调用AI笑脸识别
async function drawCanvasImage() {
await canvasimg(0.9); //绘制canvas图片函数
updateResults(document.getElementById('mycanvas'),$('#overlay').get(0)) //笑脸识别结果函数
}
TFJS表情识别逻辑处理:
官网API地址 Face-api.js
加载模型
在使用API方法前必须需加载训练好的表情模型(face_expression_model),该模型是官方成熟模型不需要自己重新进行训练,直接加载使用即可。另外所有TFJS可用的模型可在 https://github.com/justadudewhohacks/face-api.js/tree/master/weights 中查找。
表情识别逻辑
把上面实时帧获取到的人脸照片数据传递给updataResults()函数来进行人脸表情识别,这个函数依赖基础模型。该函数会笑脸识别部分有6个表情范围处理,识别到的表情数值区域会自动匹配对应扑克牌牌面,做一下判断即可。
核心代码
//笑脸加载表情模型资源
async function loadmodel() {
await getCurrentFaceDetectionNet().load('./src/json/')
await faceapi.loadFaceLandmarkModel('./src/json/')
await faceapi.loadFaceExpressionModel('./src/json/')
}
//笑脸识别结果
async function updateResults(inputimg,canvasline) {
if (!isFaceDetectionModelLoaded()) {
return
}
const inputImgEl = inputimg;
const options = getFaceDetectorOptions()
const results = await faceapi.detectAllFaces(inputImgEl, options).withFaceExpressions()
const canvas = canvasline;
faceapi.matchDimensions(canvas, inputImgEl)
const resizedResults = faceapi.resizeResults(results, inputImgEl)
const minConfidence = 0.05
faceapi.draw.drawFaceExpressions(canvas, resizedResults) //笑脸逻辑处理函数
}
//笑脸逻辑函数部分代码主要判断是否有笑脸,匹配对应牌型
if(expressIcon.text.indexOf("happy") === -1){
//无笑脸
changeCard("happyj",Domboxarr)
}else{
//有笑脸
let drawindex = expressIcon.text.indexOf("happy")
let faceexpressValue =Number(drawTextField.text[drawindex].split(" (" )[1].split(")")[0]);
if(faceexpressValue>0 && faceexpressValue<=0.2){
changeCard("happyq",Domboxarr)
}
if(faceexpressValue>0.2 && faceexpressValue<=0.7){
changeCard("happyk",Domboxarr)
}
if(faceexpressValue>0.7 && faceexpressValue<=0.8){
changeCard("happya",Domboxarr)
}
if(faceexpressValue>0.8 && faceexpressValue<=0.9){
changeCard("happy2",Domboxarr)
}
if(faceexpressValue>0.9 && faceexpressValue<=1){
changeCard("happyw",Domboxarr)
}
}
//匹配牌面函数
async function changeCard(card,Domboxarr) {
for(let i=0;i< Domboxarr.length;i++){
Domboxarr[i].classList.add(card);
}
localStorage.setItem('facexpress',card)
removenohappyfun() //删掉多于类名
}
二、图片本地下载与上传COS服务器功能
图片本地下载实现步骤:
- 先把绘制的base64图片转化为blob; (图片上传cos服务器的必须进行压缩优化)
- 接着将blod转换为file;
- 页面新建A标签,点击下载file图片文件
- 生成3份照片文件(一份小程序使用,一份大屏幕使用,一份打印机使用)
核心代码
//调用下载函数
app.downloadFileByBase64(imgScreenSrc,imgScreenName)
//以下是lib.js部分代码
//将base64转换为blob
dataURLtoBlob: function(dataurl) {
var arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
//将blob转换为file
blobToFile: function(theBlob, fileName){
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
console.log(theBlob)
return theBlob;
},
downloadFile :function (url,name='图片'){
var a = document.createElement("a")
a.setAttribute("href",url)
a.setAttribute("download",name)
a.setAttribute("target","_blank")
let clickEvent = document.createEvent("MouseEvents");
clickEvent.initEvent("click", true, true);
a.dispatchEvent(clickEvent);
},
//download img
downloadFileByBase64: function (base64,name){
var myBlob = this.dataURLtoBlob(base64)
var myUrl = URL.createObjectURL(myBlob)
this.downloadFile(myUrl,name)
}
图片上传COS服务器
- 申请腾讯云COS服务 文档地址 --- 感谢鸟哥提供部门cos接口,无需自己申请与配置
- 把本地小程序照片使用接口上传到cos服务器存储照片
问题:如果使用腾讯云sdk上传本地图片到cos服务,发现请求正常,但上传文件size:0,线上找不到图片拉取不到,你可能踩坑了....
问题分析:直接原因:服务器时间不对。细节涉及好几个问题,sdk 弄了个重传机制,第一次时间鉴权失败后,会自动校正时间,再由于是采用流式文件上传,再次重传时就拿不到文件了,这时 body 为空,所以最终的结果是请求了两次,第一次 403,第二次校正时间后请求成功了,但 body 为空,于是 cos 上就有大小为 0B 的文件
解决方案:
- 联系cos 那边的同事会改进,时间鉴权失败后,直接返回 403
- 确保本地时间与cos服务器时间一致
三、小程序云开发
模块技术负责: 熊爸
主要功能点:完成小程序用户信息与照片绑定以及照片打印状态管理相关逻辑处理
流程图:(db表使用morphy表)
小程序用户界面:
四、Node WS服务实现调用CMD命令自动连接打印机打印照片功能
简略流程图: (照片数据在局域网内)
环境配置与功能实现
- 本地打印机驱动安装
- IrfanView 软件官网下载并安装 下载地址
- 使用Node WS服务实现页面经扫码抢扫码获得打印照片信息后发出打印信息自动调用cmd命令连接打印机打印照片
照片是否被打印逻辑处理:扫码成功后修改本地打印照片json文件数据来进行打印状态管理,扫码信息已被记录或者扫码记录错误给予无法打印照片信息提示。同时本地需要添加错误日志文档,方便查看与问题定位!
欢乐麻将互动方案
互动内容概述:
- 玩家通过扫码大屏幕二维码进入游戏等待页面,倒计时结束,开始游戏;
- 游戏开始,大屏幕随机翻起13张听胡状态牌面,玩家在游戏时间内有三次点击摸牌/出牌按钮进行胡牌机会;
- 游戏过程中第一名胡牌玩家信息会同步显示到大屏幕展示,其他用户可继续玩牌直至倒计时结束;
- 胡牌玩家领取400积分可用于兑换礼物;
- 未胡牌玩家领取200积分,也可以继续参与游戏直到胡牌领取400积分,积分只可以兑换一次;
互动交互
互动视频:(非现场终版)
[##g3211ouqe2f##]
功能逻辑实现:
互动游戏中小程序用户端&大屏幕展示端所有逻辑都基于腾讯云云开发完成,实时互动方案使用云开发watch。小程序watch文档、大屏幕watch Web SDK API 文档
web端大屏幕watch方法使用公众平台登录方式调用,未选用非匿名方式登录主要考虑匿名登录对数据表操作权限过于局限,无法对数据表进行修改只能读取数据展示。
公众平台登录需扫码进行用户登录操作,避免频繁扫码认证,可以设置
const auth = app.auth({
persistence: "local" //用户显式退出或更改密码之前的30天一直有效
});
所有使用watch实时数据操作的地方,不需要watch的时候应关掉watch监听,减少性能开销
// 关闭watch
await watcher.close()
小程序互动打卡解决方案
模块技术负责: 熊爸
互动内容概述:
TGC茶馆场馆所有互动模块首次落地使用小程序打卡运营方式完成。互动模块包括两部分内容:
- 用户完成相关任务可领取积分(领积分两种类型:数据互通项目可直接领取积分无需打卡;数据无法互动的一些线下传统任务模块完成游戏后可找工作人员帮忙小程序扫码打卡领取积分)
- 积分领取后在兑换页面点击兑换礼物,需工作人员打卡进行核销
特别点赞 熊平在活动开始前仅一周时间完成所有互动模块打卡功能,为活动正常运营上线提供了强有力的技术支持!
也感谢 汤汤前期对活动的参与支持!
别问为何这么少时间,孩子只能哭
互动打卡界面:(用户端&管理端)
互动打卡视频:(非现场终版)
[##v3211kj06ny##]
功能逻辑实现:打卡领取积分、兑换奖品,管理端打卡等逻辑处理都基于小程序云开发完成。逻辑主要在:数据表设计、状态管理(打卡领积分、兑换奖品、管理员权限),细节这里就不做具体展开说明!
数据部分
数据收集包括两个维度:
1、运营侧:主要For玩家互动数据收集后,及时同步产品数据信息,决定是否调整运营方案!
2、技术侧:必须有日志记录&告警处理,便于现场紧急情况出错的问题定位,同时也方便活动结束后对整个项目总结
----------------------------------------------------------------------------------------------------------------------
正文之后...
回顾2020年,欢乐茶馆先后开张了:彭水苗乡文化茶馆、万象天地&喜茶快闪店,TGC腾讯数字文化游戏IP馆。有幸参与欢乐茶馆的每次优化迭代,看着茶馆场馆运营与互动体验不断完善,十分开心!
以下是2020年欢乐茶馆各地域IP馆概述:
一、欢乐茶馆彭水扶贫项目
《彭水苗乡扶贫.欢乐茶馆》局部图
项目主要技术支持模块:
1、玩家手机DIY苗绣,摇一摇互动上墙苗绣图案互动体验
2、苗绣文化 TVC H5
二、欢乐茶馆&喜茶快闪店(深圳万象天地)
《喜茶&欢乐茶馆》万象天地快闪店 正面图
项目主要技术支持模块:
天生一对小欢喜欢乐检测机,功能点:欢乐笑脸检测机+ 自助打印照片+大屏幕照片互动 + 小程序用户线上数据收集
三、TGC2020 欢乐茶馆IP馆
《TGC2020.欢乐茶馆》正面图
TGC2020茶馆主要互动模块:
1、欢乐检测机 --- 包括:欢乐笑脸检测机+ 自助打印照片+大屏幕照片互动 + 小程序用户线上数据收集
2、欢乐麻将机--- 沉浸式麻将游戏体验
3、多媒体斗地主互动
4、舞台弹幕互动
5、舞台互动
6、IP周边打卡
7、积分兑换
不知不觉写了这么多!本文就到此结束吧。部分细节可能未能全部展开说明清楚!如对文中细节感兴趣的童鞋可私下联系哦!当然,欢迎各位大牛给予指导与交流!
TGC2020茶馆项目团队:
馆长: rico
创意设计: 小李、猴哥、子豪
PM:苹果、七宝
开发:熊爸、晴晴