整理的人脸系列学习经验:包括人脸检测、人脸关键点检测、人脸优选、人脸对齐、人脸特征提取等过程总结,有需要的可以参考,仅供学习,请勿盗用。/TheDayIn_CSDN/article/details/93199307
思路
在做人脸状态分析过程中,需要连续保存经过人脸检测、人脸关键点检测之后,经过关键点计算的人脸旋转角度、睁眼闭眼、张嘴闭嘴等状态信息,而且需要保存五到十帧数据状态信息并统计输出,并一直连续更新人脸状态信息。所以这里考虑使用循环队列实现,主要是新建一个循环队列,在队列尾部输入没帧数据状态,在队列满之后统计状态,并删除队首一帧数据,重新再队尾插入数据,然后继续统计队列数据状态信息,这样就可以做到实时刷新状态信息。如下图示:
一、循环队列
队列是一种先进先出(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,都是顺时针从head循环至tail,所以可用此循环截止条件:
for(int i = head;i != tail + 1;i = (i + 1)%length){ //从队首一直遍历到队尾,当遍历到最后一位时,跳转至数组起始位置//特别注意此时循环截止的条件应该是i != tail + 1,因此可能tail的值小于headcout << data[i] << " ";}
完整代码实现:
#include <iostream>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的值小于headcout << 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;}