Ubunutu18.04+Qt5.14+Dlib19.24+Opencv3.4.16实时人眼监测实验

news2024/11/18 12:45:20

文章目录

  • 1 前言
  • 2 效果
  • 3 Ubuntu18.04下Qt、Opencv、Dlib的配置
    • 3.0 Ubuntu18.04的安装以及一些基本配置
    • 3.1 Qt
    • 3.2 Opencv
    • 3.3 Dlib
  • 4 核心代码
    • 4.1 pro文件
    • 4.2 Widget.cpp
    • 4.3 fatiguedetect.cpp
  • 5 资源下载


1 前言

  在Ubuntu18.04实现的一个人眼监测小程序,使用Qt5.14、Dlib19.24、Opencv3.4.16实现。
  其主要实现思想是,首先通过Opencv获取摄像头数据,然后通过Dlib提取人脸68关键点的算法对所输入图片中的人脸进行关键点检测,检测出眼部的关键点后,在用Opnecv中的画图命令进行绘制,再利用Qt进行界面展示。


2 效果

  人眼监测小程序效果如下图所示,将画面中的人眼处用绿色的线进行框选。

在这里插入图片描述


3 Ubuntu18.04下Qt、Opencv、Dlib的配置

3.0 Ubuntu18.04的安装以及一些基本配置

  U此部分涉及到buntu18.04系统的安装、配置一些基础的应用软件等过程。
  (1)引导盘的制作;(2)安装ubuntu18.04系统;(3)安装搜狗输入法;(4)安装百度网盘;(5)安装Chrome浏览器;(6)安装激活Pycharm;(7)安装VScode;
  整体的大概流程参照这篇博客

3.1 Qt

  从Qt官网下载链接https://download.qt.io/archive/qt/处下载所对应版本,我这里直接下载的是https://download.qt.io/archive/qt/5.14/5.14.2/这个页面下的这个qt-opensource-linux-x64-5.14.2.run文件.下载下来后直接命令行运行,按照步骤走即可,注意一下安装Qt的具体位置.

3.2 Opencv

  从github上下载Opencv的源码进行编译,我这次没下新版本,因为之前有用过这个Opnecv3.4.16,所以就下了这个https://github.com/opencv/opencv/tree/3.4.16版本,没有什么特别的用意,如果只是做一些小demo,仅仅用到一些opencv的基础操作如读取图片等操作,下哪个版本的都可以.
  在用到cmake-gui配置编译选项的时候,勾选编译opencv_world,这样的话所有的库文件全部打包成一个,可以简便pro文件的写法,也不用去查某个函数到底对应哪个库,这个libopencv_world.so.3.4.16也就20多MB吧.(此处是相对而言的,也可以不编译为一个库)

3.3 Dlib

  从github上下载Dlib的源码https://github.com/davisking/dlib进行编译,过程与编译opencv时类似.

4 核心代码

  本项目下的文件层级如下图所示.
在这里插入图片描述

4.1 pro文件

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++14

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    camera.cpp \
    fatiguedetect.cpp \
    main.cpp \
    widget.cpp

HEADERS += \
    camera.h \
    fatiguedetect.h \
    widget.h

FORMS += \
    widget.ui

#opencv库的路径opencv3.4.16
INCLUDEPATH += /home/ai/software/opencv3416_installed/include
LIBS += /home/ai/software/opencv3416_installed/lib/libopencv_world.so

# dlib19.24库的路径
INCLUDEPATH += /home/ai/software/dlib_installed/include
LIBS += /home/ai/software/dlib_installed/lib/libdlib.a

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

DISTFILES +=

4.2 Widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <iostream>


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    camera_thread = new Camera();
    camera_thread->set_cam_number(0);
    connect(camera_thread, SIGNAL(sendPicture(QImage)),this,SLOT(receive(QImage)));
    camera_thread->open_camera();
}

Widget::~Widget()
{
    delete ui;
}


void Widget::receive(QImage img)
{
    QImage scaled_img = img.scaled(ui->label->width(), ui->label->height());
    ui->label->setPixmap(QPixmap::fromImage(scaled_img));
}


4.3 fatiguedetect.cpp

#include "fatiguedetect.h"

// 常量定义
const double close_standard = 0.45;
const int eye_l_len = 60;

// 判断状态的类
class JudgeCondition : public QObject {
    Q_OBJECT

public:
    explicit JudgeCondition(QObject *parent = nullptr) : QObject(parent), condition(0), heavy_flag(0) {};

    void judge(std::deque<int> &left_eye_l, std::deque<int> &right_eye_l)
    {
        int left_sum = std::accumulate(left_eye_l.begin(), left_eye_l.end(), 0);
        int right_sum = std::accumulate(right_eye_l.begin(), right_eye_l.end(), 0);

        if (left_sum == eye_l_len && right_sum == eye_l_len) {
            ++heavy_flag;
            if (heavy_flag > 100) {
                condition = 3;
            } else {
                condition = 2;
            }
        } else {
            heavy_flag = 0;
            condition = 1;
        }

        emit sendCondition(condition);
    };

signals:
    void sendCondition(int);

private:
    int condition;  // 状态:0=图像缺失 1=清醒 2=疲劳 3=重度疲劳
    int heavy_flag;  // 重度疲劳标志位
};


FatigueDetect::FatigueDetect(QObject *parent) : QObject(parent),
    noImageFlag(0),
    noImage(0)
{
    cout << "[INFO] loading facial landmark predictor..." << endl;
    dlib::deserialize("./model.dat") >> predictor;          //是直接调试运行,则在build文件夹内;如果为release则与.exe在同一文件夹内
    detector = dlib::get_frontal_face_detector();
}

cv::Mat FatigueDetect::detect(cv::Mat frame)
{
    std::vector<std::vector<cv::Point>> pos;
    cv::Mat resized_frame;
    cv::resize(frame, resized_frame, cv::Size(720, 720 * frame.rows / frame.cols));
    cv::Mat gray;
//    cv::cvtColor(resized_frame, gray, cv::COLOR_BGR2GRAY);

    cv_image<bgr_pixel> dlib_img(resized_frame);

    std::vector<dlib::rectangle> rects = detector(dlib_img, 0);    //这里放入detector的必须是dlib类型参数,不能是cv::Mat,不报错,但编译时出“问题”

    if (rects.size() == 0)
    {
        noImage = 1;
        emit noSignal(noImageFlag);
    }

    for (dlib::rectangle rect : rects)    //for(类型 变量名称 : 容器/数组等内容)
    {
        noImage = 0;

        dlib::full_object_detection shape = predictor(dlib_img, rect);

        std::vector<cv::Point> pos_;

        for (int i = 36; i <= 41; i++)   //左眼关键点标识
        {
            cv::Point point(shape.part(i).x(), shape.part(i).y());
            pos_.push_back(point);
        }

        for (int i = 42; i <= 47; i++)   //右眼关键点标识
        {
            cv::Point point(shape.part(i).x(), shape.part(i).y());
            pos_.push_back(point);
        }

        pos.push_back(pos_);

        draw_point_and_line(pos_, resized_frame);
    }

    cv::Mat resized_back_frame;
    cv::resize(resized_frame, resized_back_frame, cv::Size(frame.cols, frame.rows));
    return resized_back_frame;
}

void FatigueDetect::draw_point_and_line(std::vector<cv::Point> pos_, cv::Mat &image)
{
    int linewidth = 1;
    for (int i = 0; i < 5; i++)
    {
       cv::line(image, pos_[i], pos_[i + 1], cv::Scalar(0, 255, 0), linewidth);
    }
    cv::line(image, pos_[0], pos_[5], cv::Scalar(0, 255, 0), linewidth);
    for (int i = 6; i < 11; i++)
    {
       cv::line(image, pos_[i], pos_[i + 1], cv::Scalar(0, 255, 0), linewidth);
    }
    cv::line(image, pos_[6], pos_[11], cv::Scalar(0, 255, 0), linewidth);
    for (cv::Point point : pos_)
    {
      cv::circle(image, point, linewidth, cv::Scalar(255, 0, 0), -1);
    }
}

5 资源下载

本案例中涉及到的工程文件到此处下载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/419380.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

仿京东放大镜效果的实现

仿京东放大镜 &#xff08;1&#xff09; 整个案例可以分为三个功能模块 &#xff08;2&#xff09; 鼠标经过小图片盒子&#xff0c; 黄色的遮挡层 和 大图片盒子显示&#xff0c;离开隐藏2个盒子功能 &#xff08;3&#xff09;黄色的遮挡层跟随鼠标功能。 &#xff08;4&…

百度文心一言与Notion的比较(机器人通信的例子)

文心一言出来有一段时间了&#xff0c;也经常会去问问&#xff0c;感觉对于简单的语义理解还是可以&#xff0c;其答案对于一些常见的常识等还是可以给出不错的答案&#xff0c;但是在数学与代码等方面基本上很差&#xff0c;基本的贷款利率、微积分、没有理解语义的代码等都是…

一篇五分生信临床模型预测文章代码复现——Figure 10.机制及肿瘤免疫浸润(一)

之前讲过临床模型预测的专栏,但那只是基础版本,下面我们以自噬相关基因为例子,模仿一篇五分文章,将图和代码复现出来,学会本专栏课程,可以具备发一篇五分左右文章的水平: 本专栏目录如下: Figure 1:差异表达基因及预后基因筛选(图片仅供参考) Figure 2. 生存分析,…

C++篇 ---- 命名空间namespace

由于在c语言中在定义时可能会出现重命名现象&#xff0c;造成空间冲突&#xff0c;c语言中有命名冲突&#xff1a;1 和库冲突。2 互相之间的冲突&#xff0c;变量命名冲突。所以c中就有了对其改进的关键字namespace&#xff0c;针对重定义&#xff0c;解决空间冲突。 文章目录命…

总结820

学习目标&#xff1a; 4月&#xff08;复习完高数18讲内容&#xff0c;背诵21篇短文&#xff0c;熟词僻义300词基础词&#xff09; 学习内容&#xff1a; 高等数学&#xff1a;巩固所学&#xff0c;1~10讲内容回顾 rule No.1:never lost your knowledge. rule No.2:never f…

C++基础语法(模板)

C的模板是什么&#xff1f;有什么用&#xff1f;如果你想知道问题的答案&#xff0c;那么看这篇博客就对了&#xff0c;在这篇博客中&#xff0c;我们将探讨泛型编程&#xff0c;C模板的具体内容 目录 模板概念 函数模板 显示实例化与隐式实例化 模板不支持声明和定义分离 类模…

104.(cesium篇)cesium卫星轨道模拟

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <html lang="en"> <

【数据结构】带你细致理解八大排序

文章目录前言一.冒泡排序前一个数跟后一个数比较后一个数跟前一个数比较优化复杂度与稳定性二.插入排序初始化条件从第一个元素开始初始化条件从第二个元素开始复杂度与稳定性三.选择排序一趟选出一个最小的一趟选出一个最大的和一个最小的复杂度与稳定性四.堆排序建堆用向下调…

数据结构入门(C语言版)栈和队列之栈的介绍及实现

栈栈的概念栈的实现过程栈的结构体与接口的定义1、静态栈结构2、动态栈结构3、栈的接口定义栈的接口实现①初始化栈(StackInit)②入栈(StackPush)③出栈(StackPop)④栈顶(StackTop)⑤栈元素个数(StackSize)⑥检测栈是否为空(StackEmpty)⑦销毁栈(StackDestroy)结语栈的概念 栈…

【EXata】在 Visual Studio 2010 上编译与调试 EXata

一、在 VS2010 中编译 Exata 通过命令行的形式来编译调试 EXata 的方式太过麻烦&#xff0c;一次两次还好&#xff0c;时间长了慢慢就烦了&#xff0c;于是想着有没有什么方法能够简化这些操作&#xff0c;翻看手册&#xff0c;发现是可以在 IDE 中进行编译&#xff0c;于是就有…

mysql分库分表分片分区及常见问题

1.前言 MySQL单库数据量在5000万以内性能比较好&#xff0c;超过阈值后性能会随着数据量的增大而变弱。MySQL单表的数据量是500w-1000w之间性能比较好&#xff0c;超过1000w性能也会下降。 2.mysql分布式 分库 分库一般有两种目的&#xff1a;将库中不同表进行拆分&#xff…

英国访问学者T5签证所需相关材料

英国访问学者T5签证所需相关材料,下面就随知识人网小编一起来看一看。 1、完整填写的申请表格并亲笔签名。 2、近期护照规格白色背景彩色照片并贴在签证表格首页右上角。 3、签证后至少剩余6个月有效期的护照及申请人所持有的旧护照。 4、邀请信原件。 邀请信主要内容包括&…

基于SSM框架便利店管理系统(进销存管理系统)(java+spring+springmvc+mybatis+maven+mysql+html)

一、项目简介 本项目是一套基于SSM框架便利店管理系统(进销存管理系统)&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等&#xff0c;该项目附带全部源码可作为毕设使用。…

BT8918D---huart模块分析

1 huart模块 huart模块从名字可以看出&#xff0c;用于串口UART通讯&#xff0c;H的含义&#xff0c;目前还不知道&#xff0c;待了解。该模块源码未公开&#xff0c;已经编译成库文件&#xff0c;供开发者使用。 2 huart模块分析 2.1 特性 默认特性&#xff1a; Baud rat…

R语言处理数据——janitor包的介绍及使用

janitor功能介绍 janitor可以检查并清理脏数据&#xff0c;适用于R语言用户。主要功能如下&#xff1a; 1、完美格式化数据框的列名&#xff1b; 2、创建并格式化1-3个变量的频率表&#xff0c;可以看作是一个改进的table()函数&#xff1b; 3、提供用于清理和检查数据框的其他…

CCS通过dat文件导入数据计算出结果再导出数据

之前有很多博主讲过在matlab当中导出数据&#xff0c;到DSP里面进行计算&#xff0c;然后再将数据导出到matlab当中进行使用。 以前使用过matlab当中的dat数据&#xff0c;大家可以看一下区别&#xff1a; fid fopen(A.dat,wt);%将所得的数据存在A.dat当中 fprintf(fid,%g\n…

Hadoop配置

静态IP vi /etc/sysconfig/network-scripts/ifcfg-ens33 BOOTPROTOstatic ONBOOTyes IPADDR192.168.10.11 NETMASK255.255.255.0 GATEWAY192.168.138.2 DNS1114.114.114.114 DNS28.8.8.8 重启网络服务 service network restart 修改主机名 hostnamectl set-hostname ‘hadoop…

【Vue】学习笔记03-数据绑定

学习笔记03-数据绑定v-bind 单向绑定v-model 双向绑定错误案例&#xff1a;简写总结v-bind 单向绑定 <!--准备好一个容器--><div id"root">单向数据绑定&#xff1a;<input type"text" v-bind:value"name"></div><…

C++ 实现 matlab 的 buttap 函数

文章目录1. matlab buttap 函数的功能2. matlab buttap 函数的使用方法3. C实现4. 测试1. matlab buttap 函数的功能 输入模拟低通巴特沃斯滤波器的最低阶数&#xff0c;输出对应模拟低通巴特沃斯滤波器的传递函数的零点、极点、增益 其中&#xff0c;零点都为0&#xff0c;增…

详解 OSPF 协议

今天海翎光电的小编和大家聊一聊 OSPF 协议。 OSPF 是一种基于 SPF 算法的链路状态路由协议。 上图是在一个 OSPF 区域里面添入一台新的路由器的时候&#xff0c;OSPF 协议的工作过程&#xff0c;如果你能非常详细的叙述出这张图的话&#xff0c;基本上 OSPF 协议的工作过程你…