摘 要
在我们的系统中,使用了基于 C++的智能视觉算法。开发平台为 Linux 版本的 qtcreator,方便地进行 C++程序地开发。在此基础上,利用了传统机器视觉—OPENCV 的 C++版本,对摄像头的数据进行读取和处理,以便于和 QT 进行配合显示,形成完整的可执行程序。
在人脸检测上,我们的作品采用了 OPENCV 经典算法中的级联分类器方法。同时我们选择了OpenCV 自带的 LBPHFaceRecognizer 算法,这种算法优点是不会受到太多影响,可以在性能不是很高的 ARM 板上也可执行。
在姿态识别上,我们的作品采用了 TensorFlow-Lite 框架。在轻量化推理上来说,非常适合本产品。同时,我们的作品采用了其提供的基于 CoCo 数据集的人体姿态识别 tflite 模型来进行推理,识别准确快速。
1.作品概述
1.1 背景分析
据统计,2020年我国老人已经达到了2.5亿,每年约有6000万的老人跌倒,65岁以上的老人,因为肌力衰竭等原因,每年跌倒的概率是30%至40%,而80岁以上的老人,跌倒概率已经达到了50%以上。同时,根据中国疾病控制与预防中心称,摔倒是造成老年人受伤与死亡的首要原因。据世界卫生组织统计,全球每年大约有30%的老年人发生跌倒,15%发生两次及以上,其中30余万人死亡。可以看出,跌倒已经成为了独居老人的的潜在健康风险,是老人子女家属的心腹之患。同时,由于子女不在身边,当险情发生时,老人无法自主呼救,这大大耽误了救援的黄金时间,是亟待解决的民生问题。综上所述,在家中室内装配有老人跌倒检测并向家属发出报警的功能的系统是十分必要的。
1.2 工作流程
基于对上述背景的考虑,我们提出了基于瑞萨开发平台的室内跌倒报警及防盗报警系统的设计方案,旨在守护老人的生命健康安全,为他们的老年生活保驾护航。
系统工作流程大致如下:系统在平常处于正常监控状态,当捕捉到人物出现在视野之中时,通过人脸识别实时判断目标人物的身份。若是不曾录入的人脸则发出报警通过短信形式告知家属,并且会持续一段时间通知。若系统发生了老人摔倒的情况,系统会迅速以短信告知预先存放在系统内的紧急联系人,确保老人能够得到及时的救助,同时系统会将照片上传云端,家属可以登录查看实时的情况,避免误报的产生。同时可以在系统内存入小区工作人员等能够及时通知他人及时救助。工作流程结束。
此外,亲属等人可以通过web端的应用程序实时查看屋内的情况,关注老人的身心健康安全。
1.3 特色描述
(1) 具备跌倒检测、报警功能,及防盗措施,有效保护老人人身安全。
(2) 使用图像处理技术进行人脸检测与姿态识别,技术成熟且效果良好。
(3) 通过短信、邮件、蜂鸣器报警等形式通知亲属等实施救助,具有较好的报警功能。
(4) 集成了多项云端远程服务,实现数据的快速传递和信息的实时处理。
(5) 家属可以通过web应用程序订阅通知查看数据,具有较好的交互功能。
1.4 应用前景
目前跌倒检测的主流采用人体可穿戴设备的加速度测量、视觉识别、毫米波雷达检测这三种方法。然而人体可穿戴设备智能识别部分情况,误判率高。且无法识别缓慢跌倒。同时毫米波雷达方案无法也存在着准确性问题,虚警概率较高。
在室内环境下,我们小组采用的视觉识别方案能够提供准确度的识别效果,更好的保障老人的生命健康安全。同时,亲属可以
2. 作品设计与实现
2.1 系统方案
2.2 软件流程
2.3 Web网页设计
3.结果展示
3.1移动端显示
3.2 网页端展示
4.部分核心代码
#include "FaceDiscern.h"
FaceDiscern::FaceDiscern()
{
base_dir = FACE_BASE_DIR;
index_filename = base_dir + FACE_CSV;
recognizer_filename = base_dir + FACE_XML;
recognizer_filename_1 = base_dir + FACE_XML_1;
face_detector_filename = base_dir + FACE_ALT;
model = LBPHFaceRecognizer::create(1, 8, 8, 8, DBL_MAX);
model_1 = FisherFaceRecognizer::create(0, DBL_MAX);
model->read(recognizer_filename);
model_1->read(recognizer_filename_1);
}
FaceDiscern::~FaceDiscern()
{
}
Ptr<LBPHFaceRecognizer> FaceDiscern::getModel()
{
return model;
}
bool FaceDiscern::face_train(string& filelist_txt) {//模型训练
//定义必要的变量,参数:(文件名字符串,模式(in/out)),其他参数默认
vector<Mat> mats;
vector<int> labels;
cout << filelist_txt << endl;
ifstream file(filelist_txt, ifstream::in);
if (!file.is_open()) {//当不是被打开
qWarning("file is not open!");
return false;//返回false
}else{
qWarning("file is open!");
}
//读取文件每一行
string lines;//定义行字符串变量
while (1) {//当不是EOF时,继续读取
//读取一行,参数:(文件流,字符串变量)
getline(file,lines);
if(file.eof()) break;
//定义字符串流
stringstream line_stream(lines);
//读取图片路径
string path;//定义路径变量
getline(line_stream,path,',');//读取路径,用逗号分隔符为结束
cout << path << endl;
//读取标签
string label;//定义标签变量
getline(line_stream,label);//读取其余部分,标签部分
cout << label << endl;
//读取路径指定的图片(彩色)
Mat img = imread(path,IMREAD_GRAYSCALE);//读取灰度图
//调整图片为128*128,参数:(原图矩阵,目标图矩阵,图尺寸,x比例,y比例,插值类型)
resize(img,img,Size(128,128),0,0,INTER_LINEAR);
//存入向量
mats.push_back(img.clone());//存入矩阵向量
labels.push_back(atoi(label.c_str()));//存入标签向量
}
//判读向量状态
if (mats.empty()||labels.empty()||mats.size()!=labels.size()) {//当向量为空,或两向量个数不相等时,返回假
return false;//返回false
}
//判断参数
if (mats.empty() || labels.empty() || mats.size()!=labels.size()) {//当向量为空,或尺寸不相等时,返回假
return false;//返回false
}
qWarning("Start trainning");
//训练模型
this->model->train(mats,labels);//参数:(矩阵向量,标签向量)
this->model_1->train(mats,labels);//参数:(矩阵向量,标签向量)
//保存模型
qWarning("trainning success,save the model");
this->model->save(recognizer_filename);//参数:(文件名字符串)
this->model_1->save(recognizer_filename_1);//参数:(文件名字符串)
return true;//返回真
}
bool FaceDiscern::update_face(vector<Mat>& mats, vector<int>&labels) {//更新训练模型
//判断参数
if (mats.empty() || labels.empty() || mats.size() != labels.size()) {//当向量为空,或尺寸不相等时,返回假
return false;//返回false
}
//更新训练模型
this->model->update(mats, labels);//参数:(矩阵向量,标签向量)
//保存模型
this->model->save(recognizer_filename);//参数:(文件名字符串)
return true;//返回真
}
vector<int> FaceDiscern::face_predict(vector<Mat>& testImages){//face预测函数
//定义结果向量
vector<int> result;
//判断向量合法性
if (testImages.empty()) {//当向量为空时
qWarning("no input image");
return result;//返回空的结果向量
}
if(this->model->empty()){//当模型为空
qWarning("face model load fault!");
return result;//返回空的结果向量
}
if(this->model_1->empty()){//当模型为空
qWarning("face model load fault!");
return result;//返回空的结果向量
}
//定义必要的变量
int label = -1;//标签变量
//循环遍历矩阵向量
for (long unsigned int i = 0; i < testImages.size();i++) {
//预测分类结果,参数:(图矩阵,标签变量,置信概率变量)
this->model->predict(testImages[i],label, confidence_distance);
// this->model_1->predict(testImages[i],label, confidence_distance);
cout << confidence_distance << endl;
if (confidence_distance>85 && confidence_distance<200) {//当置信距离大于80时,给标签-1表示未知
label = -1;//标签给-1
}
//存入向量
result.push_back(label);
}
return result;//返回向量
}
bool FaceDiscern::face_find(Mat& frame_input, vector<Mat>& testImages)
{
cout << "******************Try to find face_find xml*****************" << endl;
cout << face_detector_filename << endl;
ifstream file(face_detector_filename, ifstream::in);
if (!file.is_open()) {//当不被打开
qWarning("face_find file is not open!");
cout <<"/-----------------------------------------------------------/" << endl;
return false;//返回false
}else{
qWarning("file is open!");
}
CascadeClassifier cascade_face(face_detector_filename);//定义级联分类器
vector<Rect> face_rects;
Rect rect;
cascade_face.detectMultiScale(frame_input, face_rects, 1.09, 1, 0, Size(200, 200), Size(400, 400));//识别脸
if (face_rects.empty()) {//当向量为空时
return false;
}
//保存脸和绘制脸位置
for (long unsigned int i = 0; i < face_rects.size(); i++) {//循环脸向量位置
//获得人脸部分矩形
rect = face_rects[i];
//发现脸并存入矩阵向量
Mat dst;//定义新图
//调整脸图片大小,128*128,参数:(原图,目标图,尺寸,x比例,y比例,线性插值类型)
resize(frame_input(rect), dst, Size(128, 128), 0, 0, INTER_LINEAR);
cvtColor(dst, dst, COLOR_BGR2GRAY);
testImages.push_back(dst.clone());//添加到脸向量,需要clone()操作
//绘制识别脸位置矩形,参数:(图,矩形变量,颜色,线宽,线型,偏移量)
rectangle(frame_input, Rect(rect.x,rect.y,rect.width,rect.height),Scalar(255,0,0),1,8,0);
}
return true;
}
有需要的可私信或者评论联系博主噢!