1.1 前言
随着社会经济和科学技术的飞速发展,人们的生活变得更加智能化、科学化。信息安全逐渐引起人们的关注,信息的应用不断进入人们的视野。普通的身份识别方式并不能有效保证信息安全。生物识别技术以其稳定性、独特性和高效性逐渐成为人们广泛关注和研究的对象。常见的生物识别技术有很多,比如虹膜、指纹、人脸等。其中,人脸识别技术正逐渐走向成熟。这一发展使得利用人脸识别技术进行身份识别和认证成为一种新的识别发展趋势。此前,人脸识别技术的应用主要应用于安防、金融等领域,而现在人脸识别技术无处不在。仔细观察可以发现,刷脸设备应用到生活的方方面面,如高铁站刷脸验票机、商业店铺刷脸缴费机、宿舍刷脸门禁系统等。
1.2 计算机视觉
人脸识别技术就是属于计算机视觉的一个具体应用,计算机视觉具体的说,就是让机器去识别摄像机拍摄的图片或视频中的物体,检测出物体所在的位置,并对目标物体进行跟踪,从而理解并描述出图片或视频里的场景和故事,以此来模拟人脑视觉系统。因此,计算机视觉也通常被叫做机器视觉,其目的是建立能够从图像或者视频中“感知”信息的人工系统。
计算机视觉技术经过几十年的发展,已经在交通(车牌识别、道路违章抓拍)、安防(人脸闸机、小区监控)、金融(刷脸支付、柜台的自动票据识别)、医疗(医疗影像诊断)、工业生产(产品缺陷自动检测)等多个领域应用,影响或正在改变人们的日常生活和工业生产方式。未来,随着技术的不断演进,必将涌现出更多的产品和应用,为我们的生活创造更大的便利和更广阔的机会。
本次设计选择的深度学习平台是PaddlePaddle的(EasyDL)框架,飞桨为计算机视觉任务提供了丰富的API,并通过底层优化和加速保证了这些API的性能。同时,飞桨还提供了丰富的模型库,覆盖图像分类、检测、分割、文字识别和视频理解等多个领域。用户可以直接使用这些API组建模型,也可以在飞桨提供的模型库基础上进行二次研发。
1.3 PaddlePaddle框架
飞桨开源框架(PaddlePaddle)是一个易用、高效、灵活、可扩展的深度学习框架,PaddlePaddle的EasyDL图像框架底层结合百度 AutoDL/AutoML技术,针对用户数据能够自动获得最优模型和最优超参组合,进而基于少量数据就能获得出色性能和模型效果,飞桨深学习框架与自动模型搜索相结合,以确保领先的模型效果。在训练图像分类和目标检测模型时,支持多种算法,以满足不同场景对性能和效果的不同要求。传输模型是百度开发的AutoDL技术之一。结合模型网络结构搜索、转移学习技术和用户数据自动优化。与一般算法相比,训练时间更长,但更适合于子分类场景。例如,通用算法可用于区分猫和狗,但如果要区分不同品种的猫,则AutoDL效果会更好,训练完成后,可将模型部署在公有云服务器、私有服务器,封装成可离线运行的设备端SDK,或直接购买软硬一体方案,灵活适配各种使用场景及运行环境。飞桨为计算机视觉任务提供了丰富的API,并通过底层优化和加速保证了这些API的性能。同时,飞桨还提供了丰富的模型库,覆盖图像分类、检测、分割、文字识别和视频理解等多个领域。用户可以直接使用这些API组建模型,也可以在飞桨提供的模型库基础上进行二次研发。
1.4 课堂考勤设计
(1) 考勤系统功能介绍
当前的人脸考勤识别系统主要分为两大部分: 1. 人脸的识别对比 2.考勤软件界面设计与逻辑处理。
软件主要是应用在高校给学生进行考勤、签到处理,所有在功能上需要健全,支持人脸签到,支持输入学号签到,支持添加学生,支持删除学生;在界面上也支持请假管理,需要请假的学生在界面上录入请假事由,方便上课老师了解该学生的详细情况;在录入学生信息的同时,输入了学生的学号、电话、姓名、专业等信息,在学生迟到没有上课的时候,老师可以通过电话进行联系,了解情况。以前高校考勤都是老师点名实现记录的,这样比较浪费课堂时间,有了这套支持人脸识别的系统,学生路过的时候就直接进行考勤签到,非常方便,也不需要学生进行拿笔进行纸质签到,提高了整体的课堂效率。
为了灵活应对不同的考勤时间段,软件上支持设置考勤时间范围,上课老师可以进行灵活设置时间范围,这样就可以根据平时签到考勤的比例计算期末的平时成绩,提高了老师的效率。
(2)考勤系统功能实现
当前介绍设计界面,编写接口,完成整个软件的设计,接下来介绍整个软件的操作流程及接口设计进。软件的界面是采用跨平台的QT框架设计,语言采用C 语言,执行效率高,代码简洁容易理解,设计的软件主界面如下图一所示:
图1 系统主界面图
软件一共有7个功能界面,加上登录页面一共有8个界面,登录界面设计了数据库,验证了密码账号,完成登录,登录界面的设计如下:
图2 登录界面
本系统软件主要功能涉及两个方便,第一个是人脸识别对比,第二个是考勤签到的逻辑设计,考勤是可以设置考勤的时间范围,在合理的时间范围内才能考勤签到,超过了就算迟到,界面上会进行提示,如果来早了也会进行提示,不能太早的进行打卡签到;除了人脸签到以外,还支持手动输入学号进行签到。
图3 设置考勤时间范围
图4 考勤页面
在考勤状态页面可以看到当前已经签到的学生信息,在添加学生的页面可以添加新的学生,添加学生时需要将人脸对着摄像头然后输入信息进行添加,软件运行过程中需要连接网络,如果添加成功会有弹窗进行提示,添加的学生信息存放在数据库里保存的,在飞桨的云端数据库里保存了人脸数据;学生信息添加成功之后,在学生管理页面就可以看到添加的学生信息,然后就能正常的考勤识别了。
图5 添加成功提示
图6 学生管理页面
软件考勤页面还支持请假管理,如果有学生请假了,可以在页面上进行添加管理,方便老师知道这个学生的情况。
图7 请假管理页面
(3)软件代码与界面设计
如果需要当前整个项目工程,可以去这里下载:https://download.csdn.net/download/xiaolong1126626497/85892136
摄像头操作代码:
代码语言:javascript复制//截取当前摄像头的图像
void Widget::processCapturedImage(int id,const QImage &image)
{
qDebug()<<"id:"<<id;
//注册新的学生、保存人脸到目录
if(word_mode==0)
{
add_student(image);
}
//签到
else if(word_mode==1)
{
FindFace(image);
}
}
//更新摄像头
void Widget::on_pushButton_UpdateCameraNumber_clicked()
{
Find_CameraNumber();
}
//查找系统可用摄像头
void Widget::Find_CameraNumber()
{
//清空列表
ui->comboBox_camera_number->clear();
/*查找电脑当前可用摄像头*/
cameras = QCameraInfo::availableCameras();
if(cameras.count())
{
for(int i=0;i<cameras.count();i )
{
ui->comboBox_camera_number->addItem(tr("%1").arg(i));
}
ui->pushButton_start_camera->setEnabled(true);
}
else
{
QMessageBox::warning(this,tr("提示"),"本机没有可用的摄像头!n");
ui->pushButton_start_camera->setEnabled(false);
}
}
//启动摄像头
void Widget::on_pushButton_start_camera_clicked()
{
//摄像头启动标志
if(camera_flag) //如果摄像头已经启动一次,再次启动需要将之前的空间释放掉
{
camera->stop();
delete camera;
ui->horizontalLayout_camera->removeWidget(videoWidget);
delete videoWidget;
}
camera_flag=1; //标志摄像头已经启动一次
//摄像头启动之后,就无法在重复启动
ui->pushButton_start_camera->setEnabled(false);
/*创建摄像头对象,根据选择的摄像头打开*/
camera = new QCamera(cameras.at(ui->comboBox_camera_number->currentIndex()));
/*构造捕获的对象*/
camera_image_capture = new QCameraImageCapture(camera);
/*设置捕获的目的地*/
camera_image_capture->setCaptureDestination(QCameraImageCapture::CaptureToFile);
//设置截图输出、缓冲区格式、分辨
camera_image_capture->setCaptureDestination(QCameraImageCapture::CaptureToBuffer);
camera_image_capture->setBufferFormat(QVideoFrame::PixelFormat::Format_Jpeg);
//设置截图的图片尺寸
iamge_setting.setResolution(320,240);
camera_image_capture->setEncodingSettings(iamge_setting);
//关联捕获的信号,发出捕获截图信号时,发出信号
connect(camera_image_capture,&QCameraImageCapture::imageCaptured,this,&Widget::processCapturedImage);
/*配置摄像头捕获模式为帧捕获模式*/
camera->setCaptureMode(QCamera::CaptureViewfinder);
videoWidget = new QVideoWidget();
videoWidget->setMinimumSize(320,240);
//将摄像头显示窗口加入到布局中
ui->horizontalLayout_camera->insertWidget(0,videoWidget);
/*设置取景器显示*/
camera->setViewfinder(videoWidget);
/*启动摄像头*/
camera->start();
}
登录界面代码:
代码语言:javascript复制#include "LoginWindow.h"
#include "ui_LoginWindow.h"
LoginWindow::LoginWindow(QWidget *parent) :
QWidget(parent),
ui(new Ui::LoginWindow)
{
ui->setupUi(this);
this->setWindowTitle("欢迎使用人脸识别课堂考勤系统");
//设置主题样式
SetStyle(":/blue.css");
//设置密码框为密码显示模式
ui->lineEdit_password->setEchoMode(QLineEdit::Password);
//设置背景提示文字
ui->lineEdit_password->setPlaceholderText("请输入密码");
//设置背景提示文字
ui->lineEdit_user_name->setPlaceholderText("请输入用户名");
//读配置
read_config();
//读取数据库
//设置并打开数据库
if (QSqlDatabase::contains(LOG_IN_DATABASE_CONNECT_NAME))
{
database = QSqlDatabase::database(LOG_IN_DATABASE_CONNECT_NAME);
}
else
{
//数据库类型
database = QSqlDatabase::addDatabase("QSQLITE",LOG_IN_DATABASE_CONNECT_NAME);
database.setDatabaseName(LOG_IN_DATABASE_NAME); //数据库名称
database.setUserName("xl"); //用户名
database.setPassword("123456"); //密码
}
//打开数据库,如果数据库存在就打开,不存在就自动创建
if(database.open()==false)
{
qDebug("数据库打开失败.请检查程序运行路径和权限.n");
}
else
{
qDebug("连接数据库成功.n");
}
//建表--存放账号密码
CreateUserPassTAB();
}
LoginWindow::~LoginWindow()
{
delete ui;
}
/*
* 设置QT界面的样式
*/
void LoginWindow::SetStyle(const QString &qssFile)
{
QFile file(qssFile);
if (file.open(QFile::ReadOnly))
{
QString qss = QLatin1String(file.readAll());
qApp->setStyleSheet(qss);
QString PaletteColor = qss.mid(20,7);
qApp->setPalette(QPalette(QColor(PaletteColor)));
file.close();
}
else
{
qApp->setStyleSheet("");
}
}
//登录
void LoginWindow::on_pushButton_Login_clicked()
{
if(ui->checkBox_save_password->isChecked())
{
//保存配置
write_config();
}
else
{
QString text;
text=QCoreApplication::applicationDirPath() "/" CONFIG;
//文件存在就删除
if(QFileInfo(text).exists())
{
QFile::remove(text);
}
}
QString user=ui->lineEdit_user_name->text();
QString pass=ui->lineEdit_password->text();
//比较密码
if(ComparePasswords(user,pass))
{
//关闭数据库文件
database.close();
//卸载数据库--释放内存
QSqlDatabase::removeDatabase(LOG_IN_DATABASE_CONNECT_NAME);
//打开主窗口
Widget *main_widget=new Widget;
main_widget->show();
//关闭当前窗口
close();
}
else
{
QMessageBox::information(this,"提示","账号或者密码错误n请重新输入.",
QMessageBox::Ok,QMessageBox::Ok);
}
}
//创建账号密码表
void LoginWindow::CreateUserPassTAB()
{
//数据库:建表,如果存在就不创建,不存在就创建
QSqlQuery sql_query(database);
//下面语句查询指定的表是否存在.
sql_query.exec(QString("select count(*) from sqlite_master where type='table' and name='%1'").arg("password"));
if(sql_query.next())
{
if(sql_query.value(0).toInt()==0)
{
qDebug("数据库表是不存在的.准备创建.n");
//创建表格 创建表格语句:create table <table_name> (f1 type1, f2 type2,…);
/* CREATE TABLE 是告诉数据库系统创建一个新表的关键字。
* CREATE TABLE 语句后跟着表的唯一的名称
* 或标识*/
/*下面的语句: 创建一个名称为password的表,字段分别是存放 账号、密码)*/
QString create_sql = "create table password(id int primary key, user varchar(100),password varchar(100))";
sql_query.prepare(create_sql);
if(!sql_query.exec())
{
Log_Text_Display("数据库表创建失败.n");
}
else
{
Log_Text_Display("数据库表创建成功.n");
//初始化的管理员密码
addPasswords(ROOT_USER,ROOT_PASSWORD);
}
}
else
{
Log_Text_Display("数据库表是存在的.不需要创建.n");
}
}
}
//显示日志
void LoginWindow::Log_Text_Display(QString text)
{
qDebug()<<text;
}
//插入数据到数据库文件
bool LoginWindow::addPasswords(QString user,QString pass)
{
//指定操作的数据库
QSqlQuery sql_query(database);
//查询最大ID
QString select_max_sql = "select max(id) from password";
int max_id = 0;
sql_query.prepare(select_max_sql);
if(!sql_query.exec())
{
Log_Text_Display("数据库最大ID查找失败.n");
}
else
{
while(sql_query.next())
{
max_id = sql_query.value(0).toInt();
}
Log_Text_Display(QString("data base max id:%1n").arg(max_id));
//添加数据
//插入数据 插入语句:insert into <table_name> values (value1, value2,…);
QString insert_sql = tr("insert into password values(?,?,?)");
sql_query.prepare(insert_sql);
//if(max_id!=0)max_id =1; //判断是否是第一次数据
sql_query.addBindValue(max_id 1); //id
sql_query.addBindValue(user); //账号
sql_query.addBindValue(pass); //密码
if(!sql_query.exec())
{
Log_Text_Display("数据插入失败.n");
}
else
{
return true;
}
}
return false;
}
//比较密码 true成功 false失败
bool LoginWindow::ComparePasswords(QString user,QString pass)
{
//指定操作的数据库
QSqlQuery sql_query(database);
//查询全部数据
sql_query.prepare("select * from password");
if(!sql_query.exec())
{
Log_Text_Display("数据库查询错误.n");
}
else
{
while(sql_query.next())
{
int id = sql_query.value(0).toInt(); //ID--主键
QString sql_user = sql_query.value(1).toString(); //账号
QString sql_pass = sql_query.value(2).toString(); //密码
//比较密码
if(user==sql_user && sql_pass==pass)
{
return true;
}
}
}
return false;
}
//读配置
void LoginWindow::read_config()
{
//读取配置文件
QString text;
text=QCoreApplication::applicationDirPath() "/" CONFIG;
QString pass;
QString user;
//判断文件是否存在
if(QFile::exists(text))
{
QFile filenew(text);
filenew.open(QIODevice::ReadOnly);
QDataStream in(&filenew); // 从文件读取序列化数据
in >> user >> pass; //提取写入的数据
filenew.close();
//设置界面值
ui->lineEdit_user_name->setText(user);
ui->lineEdit_password->setText(pass);
ui->checkBox_save_password->setChecked(true);
}
}
//写配置
void LoginWindow::write_config()
{
QString pass;
QString user;
//从UI界面获取用户的个性化配置参数
pass=ui->lineEdit_password->text();
user=ui->lineEdit_user_name->text();
/*保存数据到文件,方便下次加载*/
QString text;
text=QCoreApplication::applicationDirPath() "/" CONFIG;
QFile filesrc(text);
filesrc.open(QIODevice::WriteOnly);
QDataStream out(&filesrc);
out << user; //序列化用户名
out << pass; //序列化密码
filesrc.flush();
filesrc.close();
}