[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自己不断地调用,更新自己的信息,比如脸上的顶点啥的。

猜你喜欢

转载自blog.csdn.net/qq_51533157/article/details/126999238