当前位置: 首页 > news >正文

[AR Foundation] 人脸检测的流程

1. 基础知识:委托与事件

委托事件相关的知识 学习了大佬的文章:https://www.cnblogs.com/SkySoot/archive/2012/04/05/2433639.html
讲的很清楚

ARFaceManager负责检测人脸,与大佬的实例中的GreetingManager类似。

简单的委托使用案例(委托是为了解决类似方法的变量):

using System;

namespace TestForEventsas
{
    class Program
    {

        public class GreetingManager
        {
            //委托是为了解决类似方法的变量,因此格式是与所需要绑定的方法类似的
            //这里也就是EnglishGreeting/ChineseGreeting
            public delegate void GreetingDelegate(string name);

            public void Greetpeople(string name,GreetingDelegate MakeGreeting)
            {
                //GreetingDelegate相当于参数为方法的变量
                //那么我们就可以将  哪种语言打招呼  作为参数传入


                MakeGreeting(name);//这里就是委托的方法真正打招呼了
            }
        }

        private static void EnglishGreeting(string name)
        {
            Console.WriteLine("Good Morning," + name);
        }
        private static void ChineseGreeting(string name)
        {
            Console.WriteLine("早上好," + name);
        }
        static void Main(string[] args)
        {
            GreetingManager gm = new GreetingManager();

            //传入中文打招呼的方法   进行打招呼 
            gm.Greetpeople("jcy", ChineseGreeting);

            //传入英文打招呼的方法   进行打招呼
            gm.Greetpeople("jcy", EnglishGreeting);

        }
    }
}

当然我们知道委托有个特性:当多个方法绑定到同一个委托变量,当调用此变量,可以依次调用所有绑定的方法
于是如果我们如果用不同语言向一个人打招呼时,代码可以这样改:

using System;

namespace TestForEventsas
{
    class Program
    {

        public class GreetingManager
        {
            //委托是为了解决类似方法的变量,因此格式是与所需要绑定的方法类似的
            //这里也就是EnglishGreeting/ChineseGreeting
            public delegate void GreetingDelegate(string name);

            //由于是依次调用所有的绑定方法,我们就不用向Greetpeople函数中一个个传方法的参数了
            public GreetingDelegate MakeGreeting; 
            public void Greetpeople(string name)
            {
                if (MakeGreeting != null)// 如果有方法注册委托变量
                {
                    MakeGreeting(name);//通过委托调用方法
                }
            }
        }

        private static void EnglishGreeting(string name)
        {
            Console.WriteLine("Good Morning," + name);
        }
        private static void ChineseGreeting(string name)
        {
            Console.WriteLine("早上好," + name);
        }
        static void Main(string[] args)
        {
            GreetingManager gm = new GreetingManager();

            //这里我们使用委托的特性,当多个方法绑定时,调用委托,会依次调用每一个绑定在上的方法

            //这里我们需要做的就是注册方法

            gm.MakeGreeting += ChineseGreeting;
            gm.MakeGreeting += EnglishGreeting;

            gm.Greetpeople("jcy");

        }
    }
}

而事件是为了更好的封装。

Event 出场,它封装了委托类型的变量,使得:在类的内部,不管你声明它是public还是protected,它总是private 的。在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同。

具体为什么用Event原因看大佬的解释。

MakeGreet 事件的声明与之前委托变量 delegate1 的声明唯一的区别是多了一个 event 关键字。看到这里,在结合上面的讲解,你应该明白到:事件其实没什么不好理解的,声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。

修改代码如下:

using System;

namespace TestForEventsas
{
    class Program
    {

        public class GreetingManager
        {
            //委托是为了解决类似方法的变量,因此格式是与所需要绑定的方法类似的
            //这里也就是EnglishGreeting/ChineseGreeting
            public delegate void GreetingDelegate(string name);


            //由于是依次调用所有的绑定方法,我们就不用向Greetpeople函数中一个个传方法的参数了
            public GreetingDelegate MakeGreetingEventHandler;//这里增加了规范性,委托一般为事件名后加上EventHandler

            //事件与委托的声明也同样相似,只是增加了event的关键词而已
            public event GreetingDelegate MakeGreeting;
            public void Greetpeople(string name)
            {
                /*
                    if (MakeGreetingEventHandler != null)// 如果有方法注册委托变量
                    {
                        MakeGreetingEventHandler(name);//通过委托调用方法
                    }
                */
                //方法类似
                if (MakeGreeting != null)// 如果有方法注册委托变量
                {
                    MakeGreeting(name);//通过委托调用方法
                }
            }
        }

        
        private static void EnglishGreeting(string name)
        {
            Console.WriteLine("Good Morning," + name);
        }
        private static void ChineseGreeting(string name)
        {
            Console.WriteLine("早上好," + name);
        }
        static void Main(string[] args)
        {
            GreetingManager gm = new GreetingManager();

            //这里我们使用委托的特性,当多个方法绑定时,调用委托,会依次调用每一个绑定在上的方法

            //这里我们需要做的就是注册方法

            gm.MakeGreeting += ChineseGreeting;
            gm.MakeGreeting += EnglishGreeting;

            gm.Greetpeople("jcy");



        }
    }
}

2. 人脸检测的流程

首先是AR Face Manager 里的OnTrackablesChanged以及facesChanged事件
在这里插入图片描述
自己的C#脚本里的自定义函数OnFaceChanged函数订阅 AR Face Manager 的facesChanged事件。
在这里插入图片描述
ARFacesChangedEventArgs则为AR Face Manager检测存储的变化信息,主要内容为三个存储AR Face的数组added/updated/removed
在这里插入图片描述
大概的流程如下:

当人脸进入屏幕的瞬间,ARFaceManager检测到了人脸,并且自动帮我们创建了一个物体ARFace,并且放置到了added数组里。因而added的Count数量为1。
然后ARFaceManager不断调用OnTrackablesChanged函数。
当我们给时间faceChanged注册方法后,faceChanged不为空,从而调用我们自己定义的方法OnFaceChanged,同时将ARFaceManager检测到的人脸变化情况保存到 ARFacesChangedEventArgs 类当中,并且作为我们注册的自定义函数的参数,因此在OnFaceChanged函数中我们可以使用检测到的人脸变化。

人脸进入后,added里生成的ARFace立马转存到了updated数组当中。
此后人脸在不移开屏幕下,updated数组容量一直为1。

人脸离开的屏幕的一瞬间,此时updated数量为0,而removed数量变为1。
并且只有在人脸重新进入时,removed变为0,added数量变为1,然后立马变为0,接着updated变为1.

说明:我的人脸检测最大值为1,同时只检测一张人脸

在这里插入图片描述
当我们移除人脸时,依然可以调用removed里的ARFace
在这里插入图片描述
因此只有新的人脸进入后,之前的ARFace才会被销毁。

我们也可以从系统提供的AR Default Face找到
在这里插入图片描述
具体内容,可以从AR Face 代码组件中看。

实际上,ARFaceManager只负责检测变化信息,而检测到的人脸信息则是由AR Default Face里的AR Face代码组件更新。
在这里插入图片描述
在这里插入图片描述

因此,ARFaceManager 只生成了一张人脸,只负责检测的情况,比如是新添加的,还是一直在屏幕里的,还是从屏幕中移除的,给出位置坐标。
当一直处在屏幕里后,由ARFace自己不断地调用,更新自己的信息,比如脸上的顶点啥的。

相关文章:

  • vulnhub Pwned: 1
  • 深入理解Linux网络技术内 幕(二)——关键数据结构
  • 基于springboot,vue企业网盘系统
  • Dreamweaver:Dreamweaver软件的界面简介、安装、案例应用之详细攻略
  • Atlas数据治理
  • echarts拖动进度条,动态更新数据
  • MATLAB | MATLAB中绘图的奇淫技巧合集
  • 指针笔试题解析(4)
  • [Spring Boot 3] 整合NoSQL与构建RESTful服务
  • 基于非线规划算法的船舶能量调度
  • 二、PL/SQL 编程基础
  • NGINX源码之:ngx_open_cached_file
  • 【路径规划-机器人栅格地图】基于蚁群算法求解大规模栅格地图路径规划及避障附Matlab代码
  • SpringCache的介绍和使用
  • java-php-python-ssm艾灸减肥管理网站计算机毕业设计
  • 分享的文章《人生如棋》
  • 「译」Node.js Streams 基础
  • 【comparator, comparable】小总结
  • C学习-枚举(九)
  • HTTP 简介
  • Redis 中的布隆过滤器
  • Redis在Web项目中的应用与实践
  • tab.js分享及浏览器兼容性问题汇总
  • 订阅Forge Viewer所有的事件
  • 高度不固定时垂直居中
  • 经典排序算法及其 Java 实现
  • 免费小说阅读小程序
  • 推荐一个React的管理后台框架
  • 学习使用ExpressJS 4.0中的新Router
  • 组复制官方翻译九、Group Replication Technical Details
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #mysql 8.0 踩坑日记
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (二十四)Flask之flask-session组件
  • (强烈推荐)移动端音视频从零到上手(下)
  • (顺序)容器的好伴侣 --- 容器适配器
  • (一)appium-desktop定位元素原理
  • (转)jdk与jre的区别
  • (转)winform之ListView
  • .net core 连接数据库,通过数据库生成Modell
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。
  • .net wcf memory gates checking failed
  • .NET 使用 XPath 来读写 XML 文件
  • .NET 依赖注入和配置系统
  • .netcore 获取appsettings
  • /使用匿名内部类来复写Handler当中的handlerMessage()方法
  • @DataRedisTest测试redis从未如此丝滑
  • @RestControllerAdvice异常统一处理类失效原因
  • [ Linux 长征路第五篇 ] make/Makefile Linux项目自动化创建工具
  • [].slice.call()将类数组转化为真正的数组
  • [20190416]完善shared latch测试脚本2.txt
  • [bzoj1006]: [HNOI2008]神奇的国度(最大势算法)
  • [cocos creator]EditBox,editing-return事件,清空输入框