Dlib+Eyelike疲劳检测

Dms.pro

INCLUDEPATH +=/usr/local/opencv4.6.0/include/ \
              /usr/local/opencv4.6.0/include/opencv4/ \
              /usr/local/opencv4.6.0/include/opencv4/opencv2
INCLUDEPATH +=/usr/local/include/python3.7m/ \
              /usr/local/include/python3.7m  -Wno-unused-result -Wsign-compare  -DNDEBUG -g -fwrapv -O3 -Wall
INCLUDEPATH +=/usr/local/lib/python3.7/site-packages/numpy/core/include/numpy
INCLUDEPATH +=/opt/zzy_space/fdlib/include \
INCLUDEPATH +=/usr/local/lib/python3.7/site-packages*


LIBS +=-L/usr/local/lib/python3.7/config-3.7m-x86_64-linux-gnu/ \
       -L/usr/local/lib -lpython3.7m -lpthread -ldl  -lutil -lm  -Xlinker -export-dynamic
LIBS +=/usr/local/lib/lib*
LIBS +=/usr/local/opencv4.6.0/lib/lib*
LIBS+=/usr/local/opencv4.6.0/lib/libopencv_videoio.so
LIBS+=/usr/local/opencv4.6.0/lib/libopencv_imgcodecs.so

#LIBS +=/opt/zzy_space/dlib-19.14/build/temp.linux-x86_64-3.7/dlib_build/libdlib.a
LIBS +=/opt/zzy_space/dlib-19.14/build/dlib/libdlib.a
LIBS +=/usr/lib/liblapack.so.3


QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    Cam.cpp \
    eyelike.cpp \
    main.cpp \
    mainwindow.cpp \
    nThread.cpp \
    yolo.cpp

HEADERS += \
    Cam.h \
    eyelike.h \
    mainwindow.h \
    nThread.h \
    yolo.h

FORMS += \
    mainwindow.ui

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

DISTFILES += \
    mydetect.py

mThread.h

#ifndef NTHREAD_H
#define NTHREAD_H
//#include "eyelike.h"
#include <QThread>

class nThread : public QThread
{
public:
    nThread();
    void run();
private:
    //Eyelike e1;
};

#endif // NTHREAD_H

mThread.cpp

#include "nThread.h"
#include <dlib/opencv.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <dlib/image_processing.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include <opencv2/dnn.hpp>      // 深度学习模块
#include <QDebug>

using namespace std;
using namespace dlib;
using namespace cv;

Mat myframe;
VideoCapture mycap;
frontal_face_detector detector;
shape_predictor pos_modle;


nThread::nThread()
{
    //std::vector<cv::Mat> rgb(3);
    //cv::split(myframe, rgb);
}

void nThread::run()
{

    cout<<myframe.type()<<endl;
    detector = get_frontal_face_detector();
    deserialize("./shape_predictor_68_face_landmarks.dat") >> pos_modle;

    //dlib


}

eyelike.h

#ifndef EYELIKE_H
#define EYELIKE_H

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
//#include <queue>
//#include <math.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>


class Eyelike {
public:
    //main
    void dlib68(cv::Mat frame, Ui::MainWindow *cui);
    void detfatigue(cv::Mat frame, cv::VideoCapture cap, Ui::MainWindow *cui);
    void detectAndDisplay(cv::Mat frame, Ui::MainWindow *cui);
    cv::Mat findSkin (cv::Mat &frame);
    void findEyes(cv::Mat frame_gray, cv::Rect face, Ui::MainWindow *cui);

    //Find eye center
    cv::Mat floodKillEdges(cv::Mat &mat);
    cv::Point unscalePoint(cv::Point p, cv::Rect origSize);
    void scaleToFastSize(const cv::Mat &src,cv::Mat &dst);
    cv::Mat computeMatXGradient(const cv::Mat &mat);
    void testPossibleCentersFormula(int x, int y, const cv::Mat &weight,double gx, double gy, cv::Mat &out);
    cv::Point findEyeCenter(cv::Mat face, cv::Rect eye, std::string debugWindow);
    bool floodShouldPushPoint(const cv::Point &np, const cv::Mat &mat);

    //Find eye corner
    void createCornerKernels();
    void releaseCornerKernels();
    cv::Mat eyeCornerMap(const cv::Mat &region, bool left, bool left2);
    cv::Point2f findEyeCorner(cv::Mat region,bool left, bool left2);
    cv::Point2f findSubpixelEyeCorner(cv::Mat region, cv::Point maxP);

    //Tools
    bool rectInImage(cv::Rect rect, cv::Mat image);
    bool inMat(cv::Point p,int rows,int cols);
    cv::Mat matrixMagnitude(const cv::Mat &matX, const cv::Mat &matY);
    double computeDynamicThreshold(const cv::Mat &mat, double stdDevFactor);


public:

    //Ui::MainWindow *cui;
    //cv::Mat frame;
    //cv::VideoCapture cap;

};

#endif // EYELIKE_H

eyelike.c

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "eyelike.h"

using namespace std;
using namespace cv;
using namespace dlib;
extern frontal_face_detector detector;
extern shape_predictor pos_modle;

int m_counter = 0, m_total = 0;
int e_counter = 0, e_total = 0;
float MAR_THRESH = 0.18, EYE_AR_THRESH = 1.5;
float EYE_AR_CONSEC_FRAMES = 0.65, MOUTH_AR_CONSEC_FRAMES = 3;

#if CV_MAJOR_VERSION >= 4
#define CV_WINDOW_NORMAL                cv::WINDOW_NORMAL
#define CV_BGR2YCrCb                    cv::COLOR_BGR2YCrCb
#define CV_HAAR_SCALE_IMAGE             cv::CASCADE_SCALE_IMAGE
#define CV_HAAR_FIND_BIGGEST_OBJECT     cv::CASCADE_FIND_BIGGEST_OBJECT
#endif

#define kEyeLeft true
#define kEyeRight false

const bool kPlotVectorField = false;

// Size constants
const int kEyePercentTop = 25;
const int kEyePercentSide = 13;
const int kEyePercentHeight = 30;
const int kEyePercentWidth = 35;

// Preprocessing
const bool kSmoothFaceImage = false;
const float kSmoothFaceFactor = 0.005;

// Algorithm Parameters
const int kFastEyeWidth = 50;
const int kWeightBlurSize = 5;
const bool kEnableWeight = true;
const float kWeightDivisor = 1.0;
const double kGradientThreshold = 50.0;

// Postprocessing
const bool kEnablePostProcess = true;
const float kPostProcessThreshold = 0.97;

// Eye Corner
const bool kEnableEyeCorner = false;

cv::String face_cascade_name = "/opt/QTproject/Dms/res/haarcascade_frontalface_alt.xml";
cv::CascadeClassifier face_cascade;
std::string main_window_name = "Capture - Face detection";
std::string face_window_name = "Capture - Face";
cv::RNG rng(12345);
cv::Mat debugImage;
cv::Mat skinCrCbHist = cv::Mat::zeros(cv::Size(256, 256), CV_8UC1);


void findEyes(cv::Mat frame_gray, cv::Rect face);
cv::Point findEyeCenter(cv::Mat face, cv::Rect eye, std::string debugWindow);
cv::Point2f findEyeCorner(cv::Mat region,bool left, bool left2);
cv::Mat floodKillEdges(cv::Mat &mat);
cv::Mat matrixMagnitude(const cv::Mat &matX, const cv::Mat &matY);
double computeDynamicThreshold(const cv::Mat &mat, double stdDevFactor);
bool inMat(cv::Point p,int rows,int cols);
cv::Point2f findSubpixelEyeCorner(cv::Mat region, cv::Point maxP);

//---------------------------main-----------------------------
void Eyelike::detfatigue(Mat frame, VideoCapture cap, Ui::MainWindow *cui)
{
      if( !face_cascade.load( face_cascade_name ) )
            printf("--(!)Error loading face cascade, please change face_cascade_name in source code.\n");

      createCornerKernels();
      ellipse(skinCrCbHist, cv::Point(113, 155), cv::Size(23, 15),
               43.0, 0.0, 360.0, cv::Scalar(255, 255, 255), -1);

       if(cap.isOpened() )
       {
         while( true )
         {
           cap.read(frame);
           // mirror it
           cv::flip(frame, frame, 1);
           frame.copyTo(debugImage);

           // Apply the classifier to the frame
           if( !frame.empty() )
           {
             detectAndDisplay(frame, cui);
           }
           else
           {
             printf(" --(!) No captured frame -- Break!");
             break;
           }
           //imshow(main_window_name, eye.frame);
           //imshow(main_window_name,debugImage);

           int c = cv::waitKey(10);
           if( (char)c == 'q' ) { break; }
           if( (char)c == 'f' ) {
             imwrite("frame.png",frame);
           }

         }
       }

       releaseCornerKernels();

       return ;

}

void Eyelike::dlib68(Mat frame, Ui::MainWindow *cui)
{
    float mnum[2];

    //将图像转化为dlib中的BGR的形式
     dlib::cv_image<bgr_pixel> cimg(frame);
     //cout<<frame.type()<<endl;
    std::vector<dlib::rectangle> faces = detector(cimg);
    std::vector<full_object_detection> shapes;
    unsigned int faceNumber = faces.size();   //获取容器中向量的个数即人脸的个数
    for (unsigned int i = 0; i < faceNumber; i++)
    {
        shapes.push_back(pos_modle(cimg, faces[i]));
    }
    if(shapes.empty())
    {
        cout<<"shapes is empty"<<endl;
    }
    if (!shapes.empty())
    {
        for (int i = 36; i <= 68; i++)
        {       //用来画特征值的点
                cv::circle(frame, cvPoint(shapes[0].part(i).x(), shapes[0].part(i).y()), 1, cv::Scalar(0, 0, 255), -1);
        }

        //mouth points
        unsigned int y_50 = shapes[0].part(50).y();
        unsigned int y_52 = shapes[0].part(52).y();
        unsigned int y_56 = shapes[0].part(56).y();
        unsigned int y_58 = shapes[0].part(58).y();
        unsigned int x_48 = shapes[0].part(48).x();
        unsigned int x_54 = shapes[0].part(54).x();

        int height_mou1 = y_58 - y_50;
        int height_mou2 = y_56 - y_52;
        int length_mou = x_54 - x_48;
        float height_mou = (height_mou1 + height_mou2) / 2;        //眼睛上下距离
        if (height_mou == 0)  //当mouth闭合的时候,距离可能检测为0,宽高比出错
            height_mou = 1;

        float ar_mou = (height_mou / length_mou);
        mnum[0] = ar_mou;
        //在屏幕上显示眼睛的高度及宽高比
        //cout << "mouth宽高比" << ar_mou << endl;


        //Left Eye Points
        unsigned int x_36 = shapes[0].part(36).x();
        unsigned int y_37 = shapes[0].part(37).y();
        unsigned int y_38 = shapes[0].part(38).y();
        unsigned int x_39 = shapes[0].part(39).x();
        unsigned int y_40 = shapes[0].part(40).y();
        unsigned int y_41 = shapes[0].part(41).y();

        //Right Eye Points
        unsigned int x_42 = shapes[0].part(42).x();
        unsigned int y_43 = shapes[0].part(43).y();
        unsigned int y_44 = shapes[0].part(44).y();
        unsigned int x_45 = shapes[0].part(45).x();
        unsigned int y_46 = shapes[0].part(46).y();
        unsigned int y_47 = shapes[0].part(47).y();

        unsigned int height_left_eye1 = y_41 - y_37;            //37到41的纵向距离
        unsigned int height_left_eye2 = y_40 - y_38;            //38到40的纵向距离
        unsigned int height_right_eye1 = y_47 - y_43;            //
        unsigned int height_right_eye2 = y_46 - y_44;
        unsigned int length_left_eye = x_39 - x_36;
        unsigned int length_right_eye = x_45 - x_42;
        //眼睛上下距离
        float height_left_eye = (height_left_eye1 + height_left_eye2)/2;
        float height_right_eye = (height_right_eye1 + height_right_eye2)/2;
        float length_eye = (length_left_eye + length_right_eye)/2;

        if (height_left_eye == 0)  //当眼睛闭合的时候,距离可能检测为0,宽高比出错
            height_left_eye = 1;
        if (height_right_eye == 0)  //当眼睛闭合的时候,距离可能检测为0,宽高比出错
            height_right_eye = 1;
        //眼睛宽高比
        float ar_eye;
        ar_eye = (height_left_eye + height_right_eye) / (2 * length_eye);
        mnum[1] = ar_eye;

        //在屏幕上显示眼睛的高度及宽高比
        //cout << "mou:" <<mnum[0] << endl;
        //cout << "eye:" <<mnum[1] << endl;
        if (mnum[1] < EYE_AR_THRESH)
        {
            e_counter += 1;
        }
        else
        {
            // 如果连续2次都小于阈值,则表示进行了一次眨眼活动
            if(e_counter >= EYE_AR_CONSEC_FRAMES)
            {
                e_total += 1;
                cout<<"e_total:"<<e_total<<endl;
                cui->label_3->setText("Eye_Blink:" + QString::number(e_total,10));
                // 重置眼帧计数器
                e_counter = 0;

            }
        }

        if (mnum[0] > MAR_THRESH)
        {

            m_counter += 1;
            //Rollmouth += 1
        }
        else
        {
            if (m_counter >= MOUTH_AR_CONSEC_FRAMES)
            {

                m_total += 1;
                cout<<"m_total:"<<m_total<<endl;
                 cui->label_4->setText("Mou_Blink:" + QString::number(m_total,10));
                // 重置嘴帧计数器
                m_counter = 0;
            }
        }

        //if(waitKey(1) == 'q') return ;
        //imshow("Dlib标记", frame);
   }
}


void Eyelike::findEyes(cv::Mat frame, cv::Rect face, Ui::MainWindow *cui) {
  //cv::Mat faceROI = frame(face);
  //cv::Mat debugFace = faceROI;
    dlib68(frame, cui);
    cout<<"2"<<endl;
//----------------------------------------

    Mat frame_gray,faceROI;
    cvtColor(frame,frame_gray,CV_BGR2GRAY);
    //截取人脸ROI
    cv::Mat faceROI_rgb = frame(face);
    cvtColor(faceROI_rgb,faceROI,CV_BGR2GRAY);
    cv::Mat debugFace = faceROI_rgb;

  if (kSmoothFaceImage) {
    double sigma = kSmoothFaceFactor * face.width;
    GaussianBlur( faceROI, faceROI, cv::Size( 0, 0 ), sigma);
  }
  //-- Find eye regions and draw them
  int eye_region_width = face.width * (kEyePercentWidth/100.0);
  int eye_region_height = face.width * (kEyePercentHeight/100.0);
  int eye_region_top = face.height * (kEyePercentTop/100.0);
  cv::Rect leftEyeRegion(face.width*(kEyePercentSide/100.0),
                         eye_region_top,eye_region_width,eye_region_height);
  cv::Rect rightEyeRegion(face.width - eye_region_width - face.width*(kEyePercentSide/100.0),
                          eye_region_top,eye_region_width,eye_region_height);

  //-- Find Eye Centers
  cv::Point leftPupil = findEyeCenter(faceROI,leftEyeRegion,"Left Eye");
  cv::Point rightPupil = findEyeCenter(faceROI,rightEyeRegion,"Right Eye");
  // get corner regions
  cv::Rect leftRightCornerRegion(leftEyeRegion);
  leftRightCornerRegion.width -= leftPupil.x;
  leftRightCornerRegion.x += leftPupil.x;
  leftRightCornerRegion.height /= 2;
  leftRightCornerRegion.y += leftRightCornerRegion.height / 2;
  cv::Rect leftLeftCornerRegion(leftEyeRegion);
  leftLeftCornerRegion.width = leftPupil.x;
  leftLeftCornerRegion.height /= 2;
  leftLeftCornerRegion.y += leftLeftCornerRegion.height / 2;
  cv::Rect rightLeftCornerRegion(rightEyeRegion);
  rightLeftCornerRegion.width = rightPupil.x;
  rightLeftCornerRegion.height /= 2;
  rightLeftCornerRegion.y += rightLeftCornerRegion.height / 2;
  cv::Rect rightRightCornerRegion(rightEyeRegion);
  rightRightCornerRegion.width -= rightPupil.x;
  rightRightCornerRegion.x += rightPupil.x;
  rightRightCornerRegion.height /= 2;
  rightRightCornerRegion.y += rightRightCornerRegion.height / 2;
  cv::rectangle(debugFace,leftRightCornerRegion,200);
  cv::rectangle(debugFace,leftLeftCornerRegion,200);
  cv::rectangle(debugFace,rightLeftCornerRegion,200);
  cv::rectangle(debugFace,rightRightCornerRegion,200);
  // change eye centers to face coordinates
  rightPupil.x += rightEyeRegion.x;
  rightPupil.y += rightEyeRegion.y;
  leftPupil.x += leftEyeRegion.x;
  leftPupil.y += leftEyeRegion.y;
  // draw eye centers
  circle(debugFace, rightPupil, 3, 1234);
  circle(debugFace, leftPupil, 3, 1234);

  //-- Find Eye Corners
  if (kEnableEyeCorner) {
    cv::Point2f leftRightCorner = findEyeCorner(faceROI(leftRightCornerRegion), true, false);
    leftRightCorner.x += leftRightCornerRegion.x;
    leftRightCorner.y += leftRightCornerRegion.y;
    cv::Point2f leftLeftCorner = findEyeCorner(faceROI(leftLeftCornerRegion), true, true);
    leftLeftCorner.x += leftLeftCornerRegion.x;
    leftLeftCorner.y += leftLeftCornerRegion.y;
    cv::Point2f rightLeftCorner = findEyeCorner(faceROI(rightLeftCornerRegion), false, true);
    rightLeftCorner.x += rightLeftCornerRegion.x;
    rightLeftCorner.y += rightLeftCornerRegion.y;
    cv::Point2f rightRightCorner = findEyeCorner(faceROI(rightRightCornerRegion), false, false);
    rightRightCorner.x += rightRightCornerRegion.x;
    rightRightCorner.y += rightRightCornerRegion.y;
    circle(debugFace, leftRightCorner, 3, 200);
    circle(debugFace, leftLeftCorner, 3, 200);
    circle(debugFace, rightLeftCorner, 3, 200);
    circle(debugFace, rightRightCorner, 3, 200);
  }

  //imshow(face_window_name, faceROI_rgb);
  Mat temp;
  cvtColor(faceROI_rgb, temp, CV_BGR2RGB);//only RGB of Qt
  QImage srcQImage = QImage((uchar*)(temp.data), temp.cols, temp.rows, temp.cols * temp.channels(), QImage::Format_RGB888);
  srcQImage = srcQImage.scaled(cui->label_11->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
  cui->label_11->setPixmap(QPixmap::fromImage(srcQImage));
  cui->label_11->show();
    cout<<"1"<<endl;

}


cv::Mat Eyelike::findSkin (cv::Mat &frame) {
  cv::Mat input;
  cv::Mat output = cv::Mat(frame.rows,frame.cols, CV_8U);

  cvtColor(frame, input, CV_BGR2YCrCb);

  for (int y = 0; y < input.rows; ++y) {
    const cv::Vec3b *Mr = input.ptr<cv::Vec3b>(y);
//    uchar *Or = output.ptr<uchar>(y);
    cv::Vec3b *Or = frame.ptr<cv::Vec3b>(y);
    for (int x = 0; x < input.cols; ++x) {
      cv::Vec3b ycrcb = Mr[x];
//      Or[x] = (skinCrCbHist.at<uchar>(ycrcb[1], ycrcb[2]) > 0) ? 255 : 0;
      if(skinCrCbHist.at<uchar>(ycrcb[1], ycrcb[2]) == 0) {
        Or[x] = cv::Vec3b(0,0,0);
      }
    }
  }
  return output;
}

void Eyelike::detectAndDisplay( cv::Mat frame, Ui::MainWindow *cui) {
    std::vector<cv::Rect> faces;
    std::vector<cv::Mat> rgbChannels(3);
    cv::split(frame, rgbChannels);
    cv::Mat frame_gray = rgbChannels[2];

    //-- Detect faces
  face_cascade.detectMultiScale(frame_gray, faces, 1.1, 2, 0|cv::CASCADE_SCALE_IMAGE|cv::CASCADE_FIND_BIGGEST_OBJECT, cv::Size(150, 150) );
  for(unsigned int i = 0; i < faces.size(); i++ )
  {
    cv::rectangle(debugImage, faces[i], 1234);
  }
  //-- Show what you got
  if (faces.size() > 0)
  {

    //cv::merge(rgbChannels, frame_gray);
    findEyes(frame, faces[0], cui);
  }

}






//--------------------------FindeyeCenter-------------------------
cv::Point Eyelike::unscalePoint(cv::Point p, cv::Rect origSize)
{
  float ratio = (((float)kFastEyeWidth)/origSize.width);
  int x = round(p.x / ratio);
  int y = round(p.y / ratio);
  return cv::Point(x,y);
}

void Eyelike::scaleToFastSize(const cv::Mat &src,cv::Mat &dst)
{
  cv::resize(src, dst, cv::Size(kFastEyeWidth,(((float)kFastEyeWidth)/src.cols) * src.rows));
}

cv::Mat Eyelike::computeMatXGradient(const cv::Mat &mat) {
  cv::Mat out(mat.rows,mat.cols,CV_64F);

  for (int y = 0; y < mat.rows; ++y) {
    const uchar *Mr = mat.ptr<uchar>(y);
    double *Or = out.ptr<double>(y);

    Or[0] = Mr[1] - Mr[0];
    for (int x = 1; x < mat.cols - 1; ++x) {
      Or[x] = (Mr[x+1] - Mr[x-1])/2.0;
    }
    Or[mat.cols-1] = Mr[mat.cols-1] - Mr[mat.cols-2];
  }

  return out;
}


void Eyelike::testPossibleCentersFormula(int x, int y, const cv::Mat &weight,double gx, double gy, cv::Mat &out) {
  // for all possible centers
  for (int cy = 0; cy < out.rows; ++cy) {
    double *Or = out.ptr<double>(cy);
    const unsigned char *Wr = weight.ptr<unsigned char>(cy);
    for (int cx = 0; cx < out.cols; ++cx) {
      if (x == cx && y == cy) {
        continue;
      }
      // create a vector from the possible center to the gradient origin
      double dx = x - cx;
      double dy = y - cy;
      // normalize d
      double magnitude = sqrt((dx * dx) + (dy * dy));
      dx = dx / magnitude;
      dy = dy / magnitude;
      double dotProduct = dx*gx + dy*gy;
      dotProduct = std::max(0.0,dotProduct);
      // square and multiply by the weight
      if (kEnableWeight) {
        Or[cx] += dotProduct * dotProduct * (Wr[cx]/kWeightDivisor);
      } else {
        Or[cx] += dotProduct * dotProduct;
      }
    }
  }
}

cv::Point Eyelike::findEyeCenter(cv::Mat face, cv::Rect eye, std::string debugWindow) {
  cv::Mat eyeROIUnscaled = face(eye);
  cv::Mat eyeROI;
  scaleToFastSize(eyeROIUnscaled, eyeROI);
  // draw eye region
  //cv::rectangle(face,eye,1234);
  cv::rectangle(face,eye,1234);
  //-- Find the gradient
  cv::Mat gradientX = computeMatXGradient(eyeROI);
  cv::Mat gradientY = computeMatXGradient(eyeROI.t()).t();
  //-- Normalize and threshold the gradient
  // compute all the magnitudes
  cv::Mat mags = matrixMagnitude(gradientX, gradientY);
  //compute the threshold
  double gradientThresh = computeDynamicThreshold(mags, kGradientThreshold);
  //double gradientThresh = kGradientThreshold;
  //double gradientThresh = 0;
  //normalize
  for (int y = 0; y < eyeROI.rows; ++y) {
    double *Xr = gradientX.ptr<double>(y), *Yr = gradientY.ptr<double>(y);
    const double *Mr = mags.ptr<double>(y);
    for (int x = 0; x < eyeROI.cols; ++x) {
      double gX = Xr[x], gY = Yr[x];
      double magnitude = Mr[x];
      if (magnitude > gradientThresh) {
        Xr[x] = gX/magnitude;
        Yr[x] = gY/magnitude;
      } else {
        Xr[x] = 0.0;
        Yr[x] = 0.0;
      }
    }
  }
  //imshow(debugWindow,gradientX);
  //-- Create a blurred and inverted image for weighting
  cv::Mat weight;
  GaussianBlur( eyeROI, weight, cv::Size( kWeightBlurSize, kWeightBlurSize ), 0, 0 );
  for (int y = 0; y < weight.rows; ++y) {
    unsigned char *row = weight.ptr<unsigned char>(y);
    for (int x = 0; x < weight.cols; ++x) {
      row[x] = (255 - row[x]);
    }
  }
  //imshow(debugWindow,weight);
  //-- Run the algorithm!
  cv::Mat outSum = cv::Mat::zeros(eyeROI.rows,eyeROI.cols,CV_64F);
  // for each possible gradient location
  // Note: these loops are reversed from the way the paper does them
  // it evaluates every possible center for each gradient location instead of
  // every possible gradient location for every center.
  //printf("Eye Size: %ix%i\n",outSum.cols,outSum.rows);
  for (int y = 0; y < weight.rows; ++y) {
    const double *Xr = gradientX.ptr<double>(y), *Yr = gradientY.ptr<double>(y);
    for (int x = 0; x < weight.cols; ++x) {
      double gX = Xr[x], gY = Yr[x];
      if (gX == 0.0 && gY == 0.0) {
        continue;
      }
      testPossibleCentersFormula(x, y, weight, gX, gY, outSum);
    }
  }
  // scale all the values down, basically averaging them
  double numGradients = (weight.rows*weight.cols);
  cv::Mat out;
  outSum.convertTo(out, CV_32F,1.0/numGradients);
  //imshow(debugWindow,out);
  //-- Find the maximum point
  cv::Point maxP;
  double maxVal;
  cv::minMaxLoc(out, NULL,&maxVal,NULL,&maxP);
  //-- Flood fill the edges
  if(kEnablePostProcess) {
    cv::Mat floodClone;
    //double floodThresh = computeDynamicThreshold(out, 1.5);
    double floodThresh = maxVal * kPostProcessThreshold;
    cv::threshold(out, floodClone, floodThresh, 0.0f, cv::THRESH_TOZERO);
    if(kPlotVectorField) {
      //plotVecField(gradientX, gradientY, floodClone);
      imwrite("eyeFrame.png",eyeROIUnscaled);
    }
    cv::Mat mask = floodKillEdges(floodClone);
    //imshow(debugWindow + " Mask",mask);
    //imshow(debugWindow,out);
    // redo max
    cv::minMaxLoc(out, NULL,&maxVal,NULL,&maxP,mask);
  }
  return unscalePoint(maxP,eye);
}

bool Eyelike::floodShouldPushPoint(const cv::Point &np, const cv::Mat &mat) {
  return inMat(np, mat.rows, mat.cols);
}

cv::Mat Eyelike::floodKillEdges(cv::Mat &mat) {
  cv::rectangle(mat,cv::Rect(0,0,mat.cols,mat.rows),255);

  cv::Mat mask(mat.rows, mat.cols, CV_8U, 255);
  std::queue<cv::Point> toDo;
  toDo.push(cv::Point(0,0));
  while (!toDo.empty()) {
    cv::Point p = toDo.front();
    toDo.pop();
    if (mat.at<float>(p) == 0.0f) {
      continue;
    }
    // add in every direction
    cv::Point np(p.x + 1, p.y); // right
    if (floodShouldPushPoint(np, mat)) toDo.push(np);
    np.x = p.x - 1; np.y = p.y; // left
    if (floodShouldPushPoint(np, mat)) toDo.push(np);
    np.x = p.x; np.y = p.y + 1; // down
    if (floodShouldPushPoint(np, mat)) toDo.push(np);
    np.x = p.x; np.y = p.y - 1; // up
    if (floodShouldPushPoint(np, mat)) toDo.push(np);
    // kill it
    mat.at<float>(p) = 0.0f;
    mask.at<uchar>(p) = 0;
  }
  return mask;
}

cv::Mat *leftCornerKernel;
cv::Mat *rightCornerKernel;

// not constant because stupid opencv type signatures
float kEyeCornerKernel[4][6] = {
  {-1,-1,-1, 1, 1, 1},
  {-1,-1,-1,-1, 1, 1},
  {-1,-1,-1,-1, 0, 3},
  { 1, 1, 1, 1, 1, 1},
};

void Eyelike::createCornerKernels()
{
  rightCornerKernel = new cv::Mat(4,6,CV_32F,kEyeCornerKernel);
  leftCornerKernel = new cv::Mat(4,6,CV_32F);
  // flip horizontally
  cv::flip(*rightCornerKernel, *leftCornerKernel, 1);
}

void Eyelike::releaseCornerKernels() {
  delete leftCornerKernel;
  delete rightCornerKernel;
}

// TODO implement these
cv::Mat Eyelike::eyeCornerMap(const cv::Mat &region, bool left, bool left2) {
  cv::Mat cornerMap;

  cv::Size sizeRegion = region.size();
  cv::Range colRange(sizeRegion.width / 4, sizeRegion.width * 3 / 4);
  cv::Range rowRange(sizeRegion.height / 4, sizeRegion.height * 3 / 4);

  cv::Mat miRegion(region, rowRange, colRange);

  cv::filter2D(miRegion, cornerMap, CV_32F,
               (left && !left2) || (!left && !left2) ? *leftCornerKernel : *rightCornerKernel);

  return cornerMap;
}

cv::Point2f Eyelike::findEyeCorner(cv::Mat region, bool left, bool left2) {
  cv::Mat cornerMap = eyeCornerMap(region, left, left2);

  cv::Point maxP;
  cv::minMaxLoc(cornerMap,NULL,NULL,NULL,&maxP);

  cv::Point2f maxP2;
  maxP2 = findSubpixelEyeCorner(cornerMap, maxP);


  return maxP2;
}

cv::Point2f Eyelike::findSubpixelEyeCorner(cv::Mat region, cv::Point maxP) {

  cv::Size sizeRegion = region.size();

  cv::Mat cornerMap(sizeRegion.height * 10, sizeRegion.width * 10, CV_32F);

  cv::resize(region, cornerMap, cornerMap.size(), 0, 0, cv::INTER_CUBIC);

  cv::Point maxP2;
  cv::minMaxLoc(cornerMap, NULL,NULL,NULL,&maxP2);

  return cv::Point2f(sizeRegion.width / 2 + maxP2.x / 10,
                     sizeRegion.height / 2 + maxP2.y / 10);
}

bool Eyelike::rectInImage(cv::Rect rect, cv::Mat image) {
  return rect.x > 0 && rect.y > 0 && rect.x+rect.width < image.cols &&
  rect.y+rect.height < image.rows;
}

bool Eyelike::inMat(cv::Point p,int rows,int cols) {
  return p.x >= 0 && p.x < cols && p.y >= 0 && p.y < rows;
}

cv::Mat Eyelike::matrixMagnitude(const cv::Mat &matX, const cv::Mat &matY) {
  cv::Mat mags(matX.rows,matX.cols,CV_64F);
  for (int y = 0; y < matX.rows; ++y) {
    const double *Xr = matX.ptr<double>(y), *Yr = matY.ptr<double>(y);
    double *Mr = mags.ptr<double>(y);
    for (int x = 0; x < matX.cols; ++x) {
      double gX = Xr[x], gY = Yr[x];
      double magnitude = sqrt((gX * gX) + (gY * gY));
      Mr[x] = magnitude;
    }
  }
  return mags;
}

double Eyelike::computeDynamicThreshold(const cv::Mat &mat, double stdDevFactor) {
  cv::Scalar stdMagnGrad, meanMagnGrad;
  cv::meanStdDev(mat, meanMagnGrad, stdMagnGrad);
  double stdDev = stdMagnGrad[0] / sqrt(mat.rows*mat.cols);
  return stdDevFactor * stdDev + meanMagnGrad[0];
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "Cam.h"
#include "eyelike.h"
#include "nThread.h"
#include <dlib/opencv.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include <dlib/gui_widgets.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include <fstream>
#include <sstream>
#include <opencv2/dnn.hpp>      // 深度学习模块
#include <string>
#include <QDebug>
#include <QMainWindow>
#include <QString>
#include <cmath>
//#include <stdlib.h>
#include <error.h>

using namespace std;

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
/*
// 自定义配置结构
struct Configuration
{
    public:
    float confThreshold; // Confidence threshold,置信度*分类分数后的阈值
    float nmsThreshold;  // Non-maximum suppression threshold,iou阈值
    float objThreshold;  //Object Confidence threshold,置信度阈值
    string modelpath;   // 模型路径
};*/


class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    //void detfatigue2(cv::Mat &myframe, cv::VideoCapture &cap, float (&mnum)[2], Ui::MainWindow &ui);
    ~MainWindow();

private slots:
    void on_Open_clicked();

public:
    QTimer *timer;
    Ui::MainWindow *ui;
    //cv::VideoCapture capture;
    //cv::Mat mframe;
    //Cam mcam;
    Eyelike meye;


private slots:
    void on_stop_clicked();
};


#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "eyelike.h"
#include<QTimer>
#include<dlib/image_processing/frontal_face_detector.h>
#include<dlib/gui_widgets.h>
#include<dlib/image_io.h>
#include<dlib/image_processing.h>

using namespace dlib;
using namespace std;
using namespace cv;

extern VideoCapture mycap;
extern Mat myframe;
extern frontal_face_detector detector;
extern shape_predictor pos_modle;


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
   //timer = new QTimer(this);
   //connect(timer, SIGNAL(timeout()), this, SLOT(importFrame()));

}

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

void MainWindow::on_Open_clicked()
{
    ui->textBrowser->setText("Camera is Opening!");
    ui->textBrowser->moveCursor(QTextCursor::End);

    mycap.open(0);
    if(!mycap.isOpened())
    {
            printf("cannot open camera!\n");
    }

    while(1)
    {
         meye.detfatigue(myframe, mycap, ui);
    }


}

void MainWindow::on_stop_clicked()
{
   mycap.release();
}

/*
void mydetect(Mat &myframe)
{
    //string img_path = "./images/bus.jpg";
    string model1_path = "/opt/QTproject/Dms/weights/best.onnx";
    string model_path = "./weights/best.onnx";

    Yolov5 test;
    Net net;
    if (test.readModel(net, model_path, false))
    {
            cout << "read net ok!" << endl;
    }
    else
    {
            return ;
    }


   std:: vector<Scalar> color;
   srand(time(0));
   for (int i = 0; i < 80; i++)
   {
            int b = std::rand() % 256;
            int g = std::rand() % 256;
            int r = std::rand() % 256;
            color.push_back(Scalar(b, g, r));
   }
   std::vector<Output> result;
   //Mat img = imread(img_path);

   if (test.Detect(myframe, net, result) == true)
   {
            cout<<"hereeee"<<endl;
            test.drawPred(myframe, result, color);

   }
   else
   {
            cout << "Detect Failed!"<<endl;
   }

        //system("pause");
        return ;
}
*/


main.cpp

#include "mainwindow.h"
#include "nThread.h"
#include <QApplication>
using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    nThread *SThread = new nThread();
    SThread->start();

    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值