基于腾讯云实时音视频(TRTC)的web端 多人人脸识别小游戏

场景介绍

在这里插入图片描述

一个双人视频互动的小游戏, 连接后,可以实时看到对方的视频情况, 根据对方的视频情况实时进行游戏操作
摇头进行控制挡板 不让球掉落。 眨眼发球。

准备工作

获取应用 SDKAppID 和 应用秘钥

登录腾讯云 搜索 实时音视频 TRTC
image.png

创建应用
在这里插入图片描述

在创建的应用上, 点击配置管理
在这里插入图片描述

在 应用概览 -》 应用信息 中获取 SDKAppID
在这里插入图片描述

在 快速上手 -》 第二步 中获取 应用秘钥
在这里插入图片描述

编码

项目设计

在这里插入图片描述

  1. 同步房主和玩家状态, 确定都处于加入房间
  2. 第一步 先推流 玩家视频
  3. 第二步 游戏画面 做辅流 和房主画面做主流 推流
  4. 第三步 识别玩家操作

代码

发送消息

音视频web端没有提供定制消息的功能, 但是提供了 sei message 进行消息发送。 原理是视频帧的头部有一个叫做 SEI 的头部数据块, 我们将数据放在这个地方 自定义消息格式, 便可以进行信息发送。
注意

其中的 sendSEIMessage 接收ArrayBuffer,  而且消息有 丢失问题。
消息格式处理, 将字符串 和 ArrayBuffer 互相转换
const string2arrayBuffer = (string: String) => {const buf = new ArrayBuffer(string.length * 2);let uint16 = new Uint16Array(buf);// 使用charCodeAt字符转为二进制编码for (var i = 0; i < string.length; i++) {uint16[i] = string.charCodeAt(i);}return uint16;
};
const arrayBuffer2string = (buff: ArrayBuffer) => {return String.fromCharCode.apply(null,new Uint16Array(buff) as unknown as Array<number>);
};

发送端多次发送, 接收端去重

// 通知
const broadcast(obj: any) {if (!this.client) return;try {const string = generateRoomCode(16) + JSON.stringify(obj);const fn = (n: number) => {if (n <= 0) return;client.sendSEIMessage(string2arrayBuffer(string).buffer, {seiPayloadType: 5,});setTimeout(() => {fn(n - 1);}, 1000 / 4);};fn(4);} catch (e) {console.log(e);}
}
// 接收消息
let getMsgList = new Set()
const handlerData = (event: any) => {let data;try {const tmpData = arrayBuffer2string(event.data);const id = tmpData.substring(0, 15);if (getMsgList.has(id)) return [];this.getMsgList.add(id);data = JSON.parse(tmpData.substring(16, tmpData.length));} catch (e) {console.log(e);}return data;
};const roomCodeOptions = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
const generateRoomCode = (len = 8) => {let code = "";for (let i = 0; i < len; i++) {const ndx = Math.floor(Math.random() * roomCodeOptions.length);code += roomCodeOptions[ndx];}return code;
};

因为发送 sei message需要先进行推流, 但是在准备阶段, 直接推送视频在流程上不太友好。 可以自定义流,我这边通过cavans 创建一个空白的流进行推送

  const publishBlack = async(userId) => {if (!client) return;try {const isCanvasCapturingSupported = () =>"captureStream" in HTMLCanvasElement.prototype;// 检测您当前的浏览器是否支持从 canvas 元素采集 streamif (!isCanvasCapturingSupported()) throw new Error("浏览器不支持");const width = 640,height = 480;const canvas = Object.assign(document.createElement("canvas"), {width,height,}) as any;// TRTC 需要检测到画面变化const timer = setInterval(() => {canvas.getContext("2d").fillRect(0, 0, width, height);}, 100);const stream = canvas.captureStream();const blackSteam = TRTC.createStream({userId,videoSource: stream.getVideoTracks()[0],});blackSteam.setVideoProfile("480p");await blackSteam.initialize();await client.publish(blackSteam);} catch (e) {console.log(e);}}

推主流 + 辅流

这个功能是SDK v4.15.0+ 版本的功能, 如果在这个版本之前 需要创建额外的Client来进行处理
推送辅流只需要 publish 加上 isAuxiliary: true 参数就可以。
推送游戏只需要游戏画面,最开始想基于屏幕共享 然后切割画面, 但是发现基于TRTC屏幕共享的类 获取到的track 并没有 cropTo方法。
直接用游戏画面的canvas 自定义流推送

createCustomStream = async (userId) => {let customStream;try {const isVideoCapturingSupported = () =>"captureStream" in HTMLVideoElement.prototype;if (!isVideoCapturingSupported()) throw new Error("浏览器不支持");const isCanvasCapturingSupported = () =>"captureStream" in HTMLCanvasElement.prototype;// 检测您当前的浏览器是否支持从 canvas 元素采集 streamif (!isCanvasCapturingSupported()) throw new Error("浏览器不支持");const stream = dom.captureStream();customStream = TRTC.createStream({userId,videoSource: stream.getVideoTracks()[0],});await customStream.initialize();await client.publish(customStream, { isAuxiliary: true });} catch (e) {console.log(e);}return customStream;
}

人脸识别

这边是直接基于开源的模型 https://github.com/tensorflow/tfjs-models/tree/master/face-landmarks-detection
在这里插入图片描述

使用模型后,会获得上面图上的坐标。 放大图片可以看清点位坐标。

左右摇头

在这里插入图片描述

我们取额头和下巴的坐标, 计算这条直线的角度。

const isSwivel = (face: any) => {if (!face || !face.keypoints) return 0;const place1 = face.keypoints[10]; //额头位置const place2 = face.keypoints[152]; //下巴位置return (Math.round((Math.atan2(place1.y - place2.y, place1.x - place2.x) * 180) / Math.PI) + 90);
};
眨眼

在这里插入图片描述

我们取眼睛的上下左右, 计算 眼睛长宽比, 调整合适的参数 进行眨眼判断

const calculateDistance = ({ x: x1, y: y1 }: any, { x: x2, y: y2 }: any) => {return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
};
let maxLeft = 0,maxRight = 0;
const detectarBlink = (face: any) => {const keypoints = face.keypoints;// 左眼上下距离const leftVertical = calculateDistance(keypoints[386], keypoints[374]);// 左眼左右距离const leftHorizontal = calculateDistance(keypoints[263], keypoints[362]);const eyeLeft = leftVertical / (2 * leftHorizontal);// 右眼上下距离const rightVertical = calculateDistance(keypoints[159], keypoints[145]);// 右眼左右距离const rightHorizontal = calculateDistance(keypoints[133], keypoints[33]);const eyeRight = rightVertical / (2 * rightHorizontal);// TODO 参数需要调整下const baseCloseEye = 0.095;const limitOpenEye = 0.14;if (maxLeft < eyeLeft) maxLeft = eyeLeft;if (maxRight < eyeRight) maxRight = eyeRight;let result = false;if (maxLeft > limitOpenEye && maxRight > limitOpenEye) {if (eyeLeft < baseCloseEye || eyeRight < baseCloseEye) {result = true;}}return result;
};
// 摇头判断
const isSwivel = (face: any) => {if (!face || !face.keypoints) return 0;const place1 = face.keypoints[10]; //额头位置const place2 = face.keypoints[152]; //下巴位置return (Math.round((Math.atan2(place1.y - place2.y, place1.x - place2.x) * 180) / Math.PI) + 90);
};

自此场景中的关键点就基本解决了。 完整代码上传到gitee上 https://gitee.com/my_zend/faceball/tree/csdn/
最终效果:
在这里插入图片描述

总结

关于实践

初期准备基于 SEI Message 信息进行游戏的同步。但是没有注意到关于sei的注意事项。
在这里插入图片描述

因为sei有丢失的可能, 需要去增加发送次数, 然后在接收端去重来保证消息的 确定性。也就导致 SEI Message并不适合,游戏场景的实时数据同步。

后面修改方案,通过推流到房主端。 房主端进行人脸识别用户操作, 同步到游戏上, 同时双流推送 房主视频和游戏视频到 玩家端。最后虽然场景勉强完成了, 但是因为房主端需要同时处理推双流、识别两个玩家操作,对于房主端的设备性能要求较高。

关于TRTC

虽然场景并不算太成功, 但是腾讯云实时音视频的api还是操作非常方便的, 其中连接处理、事件处理 大大减少了代码量,断开重连等相关功能也使得产品非常容易上手。同时还有很多云上处理, 比如云端混流 就可以缓解上面场景的人脸识别的性能问题。还有很多的功能处理, 来丰富我们的业务需求。

同时文档也是非常丰富, 跟着文档上一步一步操作, 基本不会出现太大问题。 中间遇到过的一些莫名其妙的报错,也都可以在文档上找到, 比如我在 已授权的情况下操作文件共享的时候出现 NotAllowedError: Permission denied by system 报错也能在文档上找到
在这里插入图片描述

但是也存在一些问题。 比如文档和代码上的一些不同步,在文档上存在 option, 但是 类型提示上没有
在这里插入图片描述在这里插入图片描述比如文档上没有统一描述roomId:
在这里插入图片描述
在这里插入图片描述

但是这些也只是一些小问题不没有太大影响。 而且文档也可以操作选中文本 进行文档反馈。 总体还是非常方便的

相关链接

TRTC api文档
TRTC
完整代码地址
tfjs 人脸识别模型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/28444.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ChatGPT的前生: Prompting思想

Prompt的思想是语言模型通往真正大一统的关键一步 。 ChatGPT目前大火&#xff0c;然而不少人对于ChatGPT的前辈---Prompt范式却不了解。希望通过本文&#xff0c;可以让读者对Prompt范式所蕴含的思想有所了解。本文不侧重细节的讲解&#xff0c;而重点突出Prompt范式背后的思想…

使用Python机器学习预测足球比赛结果:第一篇 数据采集 (上)

利物浦7比0狂胜曼联&#xff0c;这个锅不能再让C罗背了吧。预测足球比分有什么好方法吗&#xff1f; 微信搜索关注《Python学研大本营》&#xff0c;加入读者群&#xff0c;分享更多精彩 探索足球结果和赔率的 Python 项目。 随着数据建模成为处理随机性的强大资源&#xff0…

ChatGPT、GPT4、AutoGPT 和 MemoryGPT:初学者指南

人工智能 (AI) 不仅在改变行业&#xff0c;也在改变我们的日常生活。借助人工智能&#xff0c;我们可以改善我们的组织和生产力&#xff0c;让我们能够专注于真正重要的事情。在本文中&#xff0c;我们将探讨一些适用于日常生活的 AI 工具&#xff0c;以及它们如何帮助您保持井…

《2023 大语言模型综合能力测评报告》出炉:以文心一言为代表的国内产品即将冲出重围

近日国内与人工智能领域相关的利好政策陆续释放&#xff0c;中央召开的相关会议强调“未来要重视通用人工智能发展&#xff0c;营造创新生态。”《北京市促进通用人工智能创新发展的若干措施&#xff08;2023-2025 年&#xff09;&#xff08;征求意见稿&#xff09;》围绕五大…

我用GPT干的18件事!

给大家整理了 18 种 ChatGPT 的用法&#xff0c;看看有哪些方法是你能得上的 语法更正文本翻译语言转换代码解释修复代码错误作为百科全书信息提取好友聊天创意生成器采访问题论文大纲故事创作问题类比创建 SQL 需求情感分析将产品描述转变为广告关键字提取闲聊机器人 语法更正…

指令模板:采访大纲生成 | AIGC实践

最近收获了一些朋友的谬赞&#xff0c;说我“执行力太强了”&#xff0c;可以持续输出内容。 呃&#xff0c;其实吧&#xff0c;这些素材都是从我的实际工作和生活中来的&#xff0c;只是稍加整理而已。 要说起来&#xff0c;AIGC的出现已经完全改变了我的工作方式。在遇到问题…

每日一个 ChatGPT 使用小技巧系列之4:使用 AI 工具对 SAP ABAP 代码的编写质量进行打分

本系列之前的文章&#xff1a; 与其整天担心 AI 会取代程序员&#xff0c;不如先让 AI 帮助自己变得更强大 每日一个 ChatGPT 使用小技巧系列之1 - 给出提纲或者素材&#xff0c;让 ChatGPT 帮你写作 每日一个 ChatGPT 使用小技巧系列之2 - 用 ChatGPT 研读 SAP ABAP BAPI 的…

Vue中render函数浅浅详解

render介绍 众所周知&#xff0c;仅限于我大前端&#xff0c;Vue中的核心就是虚拟DOM。 通常我们都会把我们的页面结构逻辑都写在 template 中&#xff0c;然后再通过vue将我们的代码转换成虚拟DOM&#xff0c;相比于真实DOM&#xff0c;虚拟DOM是通过js代码处理的&#xff0c;…

Android 期末text的 浅浅复习

Android 编程题text 文章目录 前言一.预测编程题11.代码解析2.具体代码 二.预测编程题21.代码解析2.具体代码 三.预测编程题31.代码解析2.具体代码 四.预测编程题41.代码解析2.具体代码 五.预测编程题51.代码解析2.具体代码 六.预测编程题61.代码解析2.具体代码 总结 前言 个人…

浅浅地讲一下引用吧

文章目录 &#x1f384; 前言&#x1f496; 何为引用&#x1f37a;深入理解引用✈️取别名规则&#xff1a;权限只能缩小不能放大 &#x1f601; 引用的简单应用&#x1f699; 引用和指针的区别&#x1f389;结语 &#x1f384; 前言 开启C之路&#xff0c;希望看了这篇文章之…

浅浅理解.net core的路由

路由&#xff1a; web的请求到达后端服务时&#xff0c;controller(控制器)会处理传入的http请求并响应用户操作&#xff0c;请求的url会被映射到控制器的操作方法上。 此映射过程由应用程序中定义的路由规则完成。 ASP.NET.Core MVC中的路由 路由使用一对由UseRouting和UseEnd…

FPGA图像处理 浅浅浅浅浅记

FPGA因其并行处理数据、高速和可编程等特性在图像处理方面得到广泛应用&#xff0c;特别是在简单算法的时候&#xff0c;即图像处理的预处理时&#xff0c;可以通过一些FPGA开发公司所配置的软件进行对算法的实现。 Vivado的一个工具&#xff1a;System Generator 可以直接把…

UCOS(浅浅忆)

UCOS 简介UCOSIIUCOSII 移植 F1UCOSII 任务UCOSII 消息邮箱、信号量 简介 1、实时操作系统分为硬实时和软实时两类 2、UCOSII、UCOSIII的区别 1、UCOSIII新增功能 1.1 同时支持优先级与时间片调度算法 1.2 将中断任务调节交给系统任务处理&#xff0c;大大缩短中断执行时间 1…

浅浅的聊一下 WebSocket

浅浅的聊一下 WebSocket 第一次看到 ws:// 和 wss:// 时候&#xff0c;感觉好高级啊&#xff0c;还有这种协议。 Websocket 历史 WebSocket是在2008年6月诞生的1。经由IEFT标准化后&#xff0c;2009年chrome 4第一个提供了该标准支持&#xff0c;并默认启用。于2011年由IEFT标…

中关村科金张杰:ChatGPT火爆背后,对话式AI在企业服务场景面临三大挑战|MEET2023...

梦晨 发自 凹非寺量子位 | 公众号 QbitAI ChatGPT火爆&#xff0c;也让更多人看到对话式AI的商业价值。 根据艾瑞咨询发布的《2022年中国对话式AI行业发展白皮书》&#xff0c;2021年对话式AI的市场规模为45亿元&#xff0c;带动规模126亿元。 在MEET2023智能未来大会上&#x…

可怕的人工智能ChatGPT

闲来无事想看看ChatGPT作诗的水平如何&#xff0c;于是让ChatGPT模仿苏轼写一首古诗&#xff0c;第一首如下&#xff1a; 读完这首诗&#xff0c;我差点把剩下的几根头发薅下来 接下来抱着试试看的态度给ChatGPT说一下稍微具体点的要求&#xff1a; 唉&#xff0c;古诗的规则…

python统计三国演义中人物出现的频次

方式一. 简化版 安装jieba库/numpy库编程读取《三国演义》电子书&#xff0c;输出出场次数最高的10个人物名字 代码注释&#xff1a; import numpy import jieba# numpy输出有省略号的问题&#xff0c;无法显示全部数据 numpy.set_printoptions(thresholdnumpy.inf)def readF…

对行业大模型的思考

深度学习自然语言处理 分享知乎&#xff1a;黄文灏职位&#xff1a;北京智源AI研究院技术负责人 看到了 Naiyan Wang[1] 和 刘聪NLP[2] 的两篇文章&#xff0c;都提到了对行业大模型的一些看法&#xff0c;有很多相同的想法。正好身边有很多人在讨论行业大模型&#xff0c;想要…

浅谈爆火的AIGC会不会是下一个元宇宙?

OpenAI终于发布了ChatGPT安全方法&#xff0c;这距离意大利政府公开宣布全面禁止ChatGPT还不到一周。 ChatGPT对隐私规则的侵犯和版权问题的触及&#xff0c;伴随一季度迅速在全球范围内的爆火而出现。 紧随意大利的是&#xff0c;德国、日本、法国、加拿大和美国&#xff0c…