前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >web端实现AR人脸特效

web端实现AR人脸特效

作者头像
程序猿川子
发布于 2022-12-15 08:57:28
发布于 2022-12-15 08:57:28
1.5K00
代码可运行
举报
运行总次数:0
代码可运行

前言

直播、短视频、在线会议等应用越来越多地进入人们的生活,随之诞生的是丰富的各类创意玩法与新鲜体验,其中大量应用了以AI检测和图形渲染为基础的AR技术。

而随着Web技术的不断成熟,AR技术在Web上的实现成为了一种可能。今天就总结了在Web端实现此功能的几个技术要点,跟大家一起探讨一下。

架构和概念

抽象整体的实现思路如下

#bytemd-mermaid-1671094042756-0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#bytemd-mermaid-1671094042756-0 .error-icon{fill:#552222;}#bytemd-mermaid-1671094042756-0 .error-text{fill:#552222;stroke:#552222;}#bytemd-mermaid-1671094042756-0 .edge-thickness-normal{stroke-width:2px;}#bytemd-mermaid-1671094042756-0 .edge-thickness-thick{stroke-width:3.5px;}#bytemd-mermaid-1671094042756-0 .edge-pattern-solid{stroke-dasharray:0;}#bytemd-mermaid-1671094042756-0 .edge-pattern-dashed{stroke-dasharray:3;}#bytemd-mermaid-1671094042756-0 .edge-pattern-dotted{stroke-dasharray:2;}#bytemd-mermaid-1671094042756-0 .marker{fill:#333333;stroke:#333333;}#bytemd-mermaid-1671094042756-0 .marker.cross{stroke:#333333;}#bytemd-mermaid-1671094042756-0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#bytemd-mermaid-1671094042756-0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#bytemd-mermaid-1671094042756-0 .cluster-label text{fill:#333;}#bytemd-mermaid-1671094042756-0 .cluster-label span{color:#333;}#bytemd-mermaid-1671094042756-0 .label text,#bytemd-mermaid-1671094042756-0 span{fill:#333;color:#333;}#bytemd-mermaid-1671094042756-0 .node rect,#bytemd-mermaid-1671094042756-0 .node circle,#bytemd-mermaid-1671094042756-0 .node ellipse,#bytemd-mermaid-1671094042756-0 .node polygon,#bytemd-mermaid-1671094042756-0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#bytemd-mermaid-1671094042756-0 .node .label{text-align:center;}#bytemd-mermaid-1671094042756-0 .node.clickable{cursor:pointer;}#bytemd-mermaid-1671094042756-0 .arrowheadPath{fill:#333333;}#bytemd-mermaid-1671094042756-0 .edgePath .path{stroke:#333333;stroke-width:1.5px;}#bytemd-mermaid-1671094042756-0 .flowchart-link{stroke:#333333;fill:none;}#bytemd-mermaid-1671094042756-0 .edgeLabel{background-color:#e8e8e8;text-align:center;}#bytemd-mermaid-1671094042756-0 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#bytemd-mermaid-1671094042756-0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#bytemd-mermaid-1671094042756-0 .cluster text{fill:#333;}#bytemd-mermaid-1671094042756-0 .cluster span{color:#333;}#bytemd-mermaid-1671094042756-0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80,100%,96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#bytemd-mermaid-1671094042756-0:root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#bytemd-mermaid-1671094042756-0 flowchart{fill:apa;}

调取Camera获得相机画面

使用tensorflow加载人脸识别模型生成FaceMesh

根据FaceMesh生成三角网格并进行UV贴图

FaceMesh

MediaPipe Face Mesh是一种脸部几何解决方案,即使在移动设备上,也可以实时估计468个3D脸部界标。它采用 机器学习 (ML)来推断3D表面几何形状,只需要单个摄像机输入,而无需专用的深度传感器。该解决方案利用轻量级的模型架构以及整个管线中的GPU加速,可提供对实时体验至关重要的实时性能。

UVMap

UV是二维纹理坐标,U代表水平方向,V代表垂直方向。UV Map用来描述三维物体表面与图像纹理(Texture) 的映射关系,有了UV Map,我们就可以将二维的图像纹理粘贴到三维的物体表面。

矩形贴图和球面的映射图

技术实现

调取Camera获得相机画面

通过navigator.mediaDevices.getUserMedia获取stream,放到video查看。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
async function setupWebcam() {
    return new Promise( ( resolve, reject ) => {
        const webcamElement = document.getElementById( "webcam" );
        const navigatorAny = navigator;
        navigator.getUserMedia = navigator.getUserMedia ||
        navigatorAny.webkitGetUserMedia || navigatorAny.mozGetUserMedia ||
        navigatorAny.msGetUserMedia;
        if( navigator.getUserMedia ) {
            navigator.getUserMedia( { video: true },
                stream => {
                    webcamElement.srcObject = stream;
                    webcamElement.addEventListener( "loadeddata", resolve, false );
                },
            error => reject());
        }
        else {
            reject();
        }
    });
}
人脸识别
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//创建模型
createModel() {
    return new Promise(async resolve => {
        await tf.setBackend('webgl')
        const model = faceLandmarksDetection.SupportedModels.MediaPipeFaceMesh;
        const detectorConfig = {
            maxFaces: 1, //检测到的最大面部数量
            refineLandmarks: true, //可以完善眼睛和嘴唇周围的地标坐标,并在虹膜周围输出其他地标
            runtime: 'mediapipe',
            solutionPath: 'https://unpkg.com/@mediapipe/face_mesh', //WASM二进制文件和模型文件所在的路径
        };
        this.model = await faceLandmarksDetection.createDetector(model, detectorConfig);
        resolve(this.model);
    })
},
//识别
async recognition() {
    try {
        const video = this.$refs.video;
        const faces = await this.model.estimateFaces(video, {
            flipHorizontal: false, //镜像
        });
        if (faces.length > 0) {
            const keypoints = faces[0].keypoints;
            this.render3D({
                scaledMesh:keypoints.reduce((acc, pos) =>{
                    acc.push([pos.x,pos.y,pos.z])
                    return acc
                }, [])
            });
        }else{
            this.render3D({scaledMesh:[]})
        }
    } catch (error) {
        console.log(error);
    }
}
3D场景贴图
  1. TRIANGULATION
  2. UV_COORDS
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //3D场景
    const scene = new THREE.Scene();

    //添加一些光照
    scene.add( new THREE.AmbientLight( 0xcccccc, 0.4 ) );
    camera.add( new THREE.PointLight( 0xffffff, 0.8 ) );
    
    //正交相机
    scene camera = new THREE.PerspectiveCamera( 45, 1, 0.1, 2000 );
    camera.position.x = videoWidth / 2;
    camera.position.y = -videoHeight / 2;
    camera.position.z = -( videoHeight / 2 ) / Math.tan( 45 / 2 )
    scene.add( camera ); 
    
    //渲染器
    const renderer = new THREE.WebGLRenderer({
        canvas: document.getElementById( "overlay" ),
        alpha: true
    });
    
    //创建geometry,将468个人脸特征点按照一定的顺序(TRIANGULATION)组成三角网格,并加载UV_COORDS
    const geometry = new THREE.BufferGeometry()
    geometry.setIndex(TRIANGULATION)
    geometry.setAttribute('uv', new THREE.Float32BufferAttribute(UV_COORDS.map((item, index) => index % 2 ? item : 1 - item), 2))
    geometry.computeVertexNormals()
                
    //创建material
    const textureLoader = new THREE.TextureLoader();
    const meshImg = this.meshList[meshIndex].src;//材质图片地址
    textureLoader.load(meshImg,texture=>{
        texture.encoding = THREE.sRGBEncoding
        texture.anisotropy = 16
        const material = new THREE.MeshBasicMaterial({
            map: texture,
            transparent: true,
            color: new THREE.Color(0xffffff),
            reflectivity: 0.5
        });
        const mesh = new THREE.Mesh(geometry, material)
        scene.add(mesh)
    })
    // 根据face mesh实时更新geometry
    updateGeometry(prediction){
        let w = canvasWidth;
        let h = canvasWidth;
        const faceMesh = resolveMesh(prediction.scaledMesh, w, h)
        const positionBuffer = faceMesh.reduce((acc, pos) => acc.concat(pos), [])
        geometry.setAttribute('position', new THREE.Float32BufferAttribute(positionBuffer, 3))
        geometry.attributes.position.needsUpdate = true
    }
   resolveMesh(faceMesh, vw, vh){
       return faceMesh.map(p => [p[0] - vw / 2, vh / 2 - p[1], -p[2]])
   }
   
   //渲染
   render3D(prediction){
        if (prediction) {
            updateGeometry(prediction)
        }
        renderer.render(scene, threeCamera)
    }
加载3D模型
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//加载3D模型
const loader = new GLTFLoader();
const Object3D = new THREE.Object3D();
loader.load(modelUrl, (gltf) => {
    const object = gltf.scene
    const box = new THREE.Box3().setFromObject(object)
    const size = box.getSize(new THREE.Vector3()).length()
    const center = box.getCenter(new THREE.Vector3())
    object.position.x += (object.position.x - center.x);
    object.position.y += (object.position.y - center.y + 1);
    object.position.z += (object.position.z - center.z - 15);
    Object3D.add(object)
    this.scene.add(Object3D)
})

//计算Matrix
const position = prediction.midwayBetweenEyes[0]
const scale = this.getScale(prediction.scaledMesh, 234, 454)
const rotation = this.getRotation(prediction.scaledMesh, 10, 50, 280)
object.position.set(...position)
object.scale.setScalar(scale / 20)
object.scale.x *= -1
object.rotation.setFromRotationMatrix(rotation)
object.rotation.y = -object.rotation.y
object.rotateZ(Math.PI)
object.rotateX(-Math.PI * .05)
if (this.morphTarget) {
    // flipped
    this.morphTarget['leftEye'] && this.morphTarget['leftEye'](1 - prediction.faceRig.eye.r)
    this.morphTarget['rightEye'] && this.morphTarget['rightEye'](1 - prediction.faceRig.eye.l)
    this.morphTarget['mouth'] && this.morphTarget['mouth'](prediction.faceRig.mouth.shape.A)
}

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
特殊客户端环境下FTP访问异常,换软件、换主被动模式
FTP客户端环境多种多样,有些FTP客户端需要显式操作来启用被动连接,有些客户端甚至不支持被动连接只能用主动模式。而一些客户端试图在发生网络错误时智能地在这两种模式之间切换。
Windows技术交流
2021/11/09
2.6K0
≥2012R2 配置IIS FTP
运行powershell输入Get-WindowsFeature -Name NET-*, Web-* | where {$_.Name -notmatch "Web-Application-Proxy"} | Install-WindowsFeature这句命令就可以了
Windows技术交流
2021/06/13
2.6K0
OMV -6- 搭建并使用公网 SFTP 服务
默认情况下FTP协议使用TCP端口中的20和21这两个端口。21端口用于传输控制信息,而是否使用20作为传输数据的端口与FTP使用的传输模式有关,如果采用被动模式则具体使用哪个端口要服务器端和客户端协商决定。FTP传输模式分为以下两种:
为为为什么
2022/08/06
4.2K0
OMV -6- 搭建并使用公网 SFTP 服务
如何快速从本地上传文件到windows server 服务器中
使用mini-sftp-server软件来快速建立一个sftp服务器端,然后本地通过filezilla或xftp或其他ftp客户端软件就行
余生尽起孤独
2024/10/08
3350
云服务器 便捷 上传、下载文件
centos安装rzsz的命令:yum install lrzsz ,卸载:yum remove lrzsz
Windows技术交流
2020/03/21
24.4K0
Windows Server系统配置SFTP服务传输文件
我们在使用Windows Server系统的服务器时,经常会遇到从服务器给本地下载文件,或者从本地电脑给服务器上上传文件的场景,对于这种场景一般有如下几种方法:
夏日萤火
2025/01/11
5540
Windows远程复制粘贴大文件不稳定如何解决
http://coreftp.com/server/download/mini-sftp-server.exe
Windows技术交流
2019/12/20
3.1K0
上传下载大文件,不要远程复制粘贴,sftp长连接,网络不好就用它
Windows服务器远程复制粘贴大文件,又卡又慢,微软官网推荐了一种貌似OK的办法
Windows技术交流
2020/11/21
4.8K8
FileZilla 错误:Server unexpectedly closed network connection 无法连接到服务器
有些linux系统比较老(比如sles11sp3),新版的filezilla client版本比较高(实际是FileZilla FTP Client里的fzputtygen.exe和fzsftp.exe版本比较高)导致CipherSuite密码套件不兼容而出现下图报错,详情见filezilla官网bug说明(这个说明是我定位清楚问题后才意外搜到的,要是早点搜到也不必花好几个小时去排障了)
Windows技术交流
2019/12/23
11.3K0
FileZilla Server提权与常见问题
FileZilla是一款非常流行的免费、开源FTP软件,分为客户端FileZilla Client和服务器端FileZilla Server两个版本,具备所有FTP软件功能。可控性、有条理的界面和管理多站点的简化方式使得FileZilla Client成为一个方便高效的FTP客户端工具,而FileZilla Server则是一个小巧且支持FTP、FTPS、SFTP等文件传输协议的FTP服务器软件,官方网站:https://filezilla-project.org/。
潇湘信安
2022/09/22
3.2K0
FileZilla Server提权与常见问题
sftp.exe、ftp.exe命令行对比,都不太好用,前者稍好些
经验证,服务端配置openssh server,客户端用sftp.exe命令是可以操作的,也不用区分主被动模式,具有通用性,效率也高。
Windows技术交流
2024/10/14
1630
Web基础配置篇(八): 远程操作工具、命令的介绍、安装及基本使用
我们做web服务开发,难免要进行测试、生产的发版,脚本的撰写,因此,远程登录操作是很常见的,下面总结下Linux常用工具的使用,顺便说下windows上的一些远程控制工具,后面着重讲下连接linux服务器的工具及常用命令。毕竟是Web开发工具嘛,当然要将web相关的。
品茗IT
2019/09/12
2.1K1
Web基础配置篇(八): 远程操作工具、命令的介绍、安装及基本使用
腾讯云堡垒机文件上传下载
背景:已经完成了堡垒机基本配置之后,运维人员已经可以访问到相应的资源机,但是运维工作需要向资源机上传下载文件要如何操作了要如何管控,接下来介绍下使用堡垒机如何向资源机上传或下载文件
陈游生
2021/03/09
12.6K0
腾讯云堡垒机文件上传下载
翼龙面板保姆级教程汇总 ( Pterodactyl )
翼龙面板是一个开源的,用于游戏服务器管理的程序,可以方便地在网页界面中创建Minecraft,起源引擎游戏和Teamspeak3 服务器。 它使用前后端程序,因此可以创建多后端节点,对游戏服务器和服务器节点进行统一管理。 对游戏配置文件的自定义支持允许我们自由地配置不同需求的游戏服务器。
阿龙w
2022/12/02
8.4K5
翼龙面板保姆级教程汇总 ( Pterodactyl )
WinNTSetup极大简化Windows系统安装
这是我在云服务器Windows Server2019系统的基础上用WinNTSetup安装的三合一系统
Windows技术交流
2020/03/13
7.4K6
windows 应急流程及实战演练
当企业发生黑客入侵、系统崩溃或其它影响业务正常运行的安全事件时,急需第一时间进行处理,使企业的网络信息系统在最短时间内恢复正常工作,进一步查找入侵来源,还原入侵事故过程,同时给出解决方案与防范措施,为企业挽回或减少经济损失。
信安之路
2018/10/18
3K0
windows 应急流程及实战演练
一文了解提权:溢出提权和第三方组件提权
SUID可以让调用者以文件拥有者的身份运行该文件,所以我们利用SUID提权的思路就是运行root用户所拥有的SUID的文件,那么我们运行该文件的时候就得获得root用户的身份了
红客突击队
2022/09/29
1.8K0
一文了解提权:溢出提权和第三方组件提权
10 分钟带你从入门到精通的 Docker 小白实战教程
笔者:花生 PeA,百度前端汪、ACGer。个人博客:pea3nut.blog;个人资料:pea3nut.info。
iMike
2019/10/15
2.2K0
服务器安全部署文档(转载)
  年前一直在赶项目,到最后几日才拿到新服务器新添加的硬盘,重做阵列配置生产环境,还要编写部署文档做好安全策略,交给测试部门与相关部门做上线前最后测试,然后将部署文档交给相关部门同事,让他根据部署文档再做一次系统,以保证以后其他同事能自己正常部署服务器,最后终于赶在放假前最后一天匆忙搞定测试后,简单的指导同事按部署文档将服务器重新部署了一次就先跑路回家了,剩下的就留给加班的同事负责将服务器托管到机房了。年后回来上班后按工作计划开始做文档(主要对之前编写的部署文档进行修正和将相关未添加的安全策略添加进文档中,并在测试环境进行安全测试)。等搞定后要对服务器做最后一次安全检查时,运营部门已将网站推广出去了,真是晕死,都不给人活了......只能是加班加点对已挂到公网的服务器日志和相关设置项做一次体检。当然一检查发现挂出去的服务器有着各种各样的攻击记录,不过还好都防住了,没有什么问题,然后就是继续添加一些防火墙策略和系统安全设置。
张传宁IT讲堂
2019/09/17
2.3K0
服务器安全部署文档(转载)
CentOS 7 常用软件安装汇总
分区 & 格式化 1. 先看看有几个物理硬盘: #fdisk -l 2. 选择一个物理硬盘来分区 #fdisk /dev/vdb1 (我这里为vdb1) 3. 进去后使用的是快捷命令: p : 查看当前分区 d:删除当前分区 n:创建一个新的分区 w: 存盘退出(所有改动生效) q: 不存盘、退出(所有改动不生效,安全) 一个一个子分区先删除干净之后才能建立新分区
全栈程序员站长
2022/09/14
5.4K0
CentOS 7 常用软件安装汇总
推荐阅读
相关推荐
特殊客户端环境下FTP访问异常,换软件、换主被动模式
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验