深度学习自学(二十一):连续保存人脸检测、关键点检测后人脸状态-循环队列实现

整理的人脸系列学习经验:包括人脸检测、人脸关键点检测、人脸优选、人脸对齐、人脸特征提取等过程总结,有需要的可以参考,仅供学习,请勿盗用。https://blog.csdn.net/TheDayIn_CSDN/article/details/93199307

思路

在做人脸状态分析过程中,需要连续保存经过人脸检测、人脸关键点检测之后,经过关键点计算的人脸旋转角度、睁眼闭眼、张嘴闭嘴等状态信息,而且需要保存五到十帧数据状态信息并统计输出,并一直连续更新人脸状态信息。所以这里考虑使用循环队列实现,主要是新建一个循环队列,在队列尾部输入没帧数据状态,在队列满之后统计状态,并删除队首一帧数据,重新再队尾插入数据,然后继续统计队列数据状态信息,这样就可以做到实时刷新状态信息。如下图示:

深度学习自学(二十一):连续保存人脸检测、关键点检测后人脸状态-循环队列实现_第1张图片

一、循环队列

队列是一种先进先出(FIFO,First-In-First-Out)的线性表,通常用链表或者数组来实现。队列只能在队尾插入元素,只能在队首删除元素。

循环队列的一些性质:

1.在循环队列里,如果容量没有达到上限,当队尾队首标记达到数组上界后,就跳转到数组起始位置

2.在线性队列里,当 tail 达到队列上限后,继续插入就会发生“假上溢”的情况

3.循环队列里可通过统计队列里元素个数,判断能否继续往队列里插入元素

首先,我们增加一个count变量来计算入队的元素个数,这样的话,当count = length的时候,才表示真正的队列“上溢”,所以呢,对于循环队列的入队操作,可分两种情况讨论:

1.如果队尾指针此时并未指向队列的最后一位,那么队尾指针直接前移 tail = tail + 1

2.当队尾指针此时指向最后一位时,那么当队列未满时,则队尾指针将跳转至数组起始位置 tail = (tail + 1)% length

3.队首元素出队列 head = (head + 1) % length

这里特别需要注意的是,循环队列的遍历输出时,循环截止条件不再是head <= tail,而是head != tail +1,这是为什么呢?原因其实也很简单,因为当队尾队首标记达到数组上界后,就跳转到数组起始位置,所以tail是可能小于head的,而无论是head tail,都是顺时针从head循环至tail,所以可用此循环截止条件:

for(int i = head;i != tail + 1;i = (i + 1)%length){     //从队首一直遍历到队尾,当遍历到最后一位时,跳转至数组起始位置
                                                                            //特别注意此时循环截止的条件应该是i != tail + 1,因此可能tail的值小于head
            cout << data[i] << " ";
        }

完整代码实现:

#include 
using namespace std;
class Queue{
private:
    int *data;              //定义指向整型的指针,从而动态开辟内存
    int head,tail,length,count;   //head指向队首,tail指向队尾,length表示队列的长度,count用于记录队列中元素个数,从而判断队列是否已满
public:
    Queue (int length_input){       //构造函数,对新声明的队列对象进行初始化
        data = new int [length_input];      //动态开辟100个整型数据的空间
        length = length_input;              //为队列的长度赋初始值
        head = 0;                       //起初head为0,表示head值未改变的情况下,一直指向首元素
        tail = -1;                      //tail初始值为-1,表示此时队列为空,无任何数据元素
        count = 0;
    }
    ~Queue(){
        delete [] data;             //析构函数,删除动态开辟的内存
    }
     void push(int element){            //入队操作,只能从队列的尾部插入数据元素
        if(count < length){             //队列未满的时候才能插入,否则则插入失败
            tail = (tail + 1) % length;     //分两种情况,如果队尾指针此时并未指向队列的最后一位,那么队尾指针直接前移,而当队尾指针此时指向最后一位时
            data[tail] = element;           //那么当队列未满时,则队尾指针将跳转至数组起始位置,再将数据元素插入队尾指针指向的位置
            ++count;                    //入队成功,队列中元素数量加一
        }
    }
    void pop(){
        if(count < 0){     //队列为空,出队失败
            return;
        }
        head = (head + 1) % length;         //同样,根据循环队列的性质得出
        --count;            //出队成功,队列中元素数量减一
    }
    int top(){
        if(count > 0){      //队列不为空的情况下才能获取队首元素
            return data[head];
        }
    }
    void output(){
        for(int i = head;i != tail + 1;i = (i + 1)%length){     //从队首一直遍历到队尾,当遍历到最后一位时,跳转至数组起始位置
                                                                //特别注意此时循环截止的条件应该是i != tail + 1,因此可能tail的值小于head
            cout << data[i] << " ";
        }
        cout << endl;
    }
};
int main() {
    Queue queue(100);               //声明一个队列对象,并初始化
     for(int i = 1;i <= 10;++i){
        queue.push(i);             //将1-10这10个数据元素依次插入队列中
    }
    queue.output();             //调用输出的方法
    cout << "当前的队首元素为:" << queue.top() << endl;
    queue.pop();               //出队
    queue.output();             //调用输出的方法
    cout << "出队操作后的队首元素为:" << queue.top() << endl;
    return 0;
}


 

你可能感兴趣的:(计算机视觉,人脸系列学习)