QT+Dlib

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "nThread.h"
#include <QMainWindow>
#include <QTimer>
#include <opencv.hpp>

using namespace cv;

//VideoCapture mycap;
//Mat myframe;

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    QImage MattoQt(cv::Mat src);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();
    void readframe();
    void mshow();

private:
    Ui::MainWindow *ui;
    QTimer *timer;
    //Mat myframe;
    //VideoCapture mycap;
    nThread0 *Thread0;
    nThread1 *Thread1;
    nThread2 *Thread2;
};
#endif // MAINWINDOW_H
.

MainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dlib.h"
#include "nThread.h"
#include <opencv2/imgproc/types_c.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 <QTime>
using namespace dlib;
using namespace cv;

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


extern float mnum[2];
extern int e_total, m_total;
extern int e_counter, m_counter;
extern float EYE_AR_THRESH, MOU_AR_THRESH;
extern float EYE_AR_CONSEC_FRAMES, MOUTH_AR_CONSEC_FRAMES;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow), Thread0(new nThread0), Thread1(new nThread1()), Thread2(new nThread2())
{
    ui->setupUi(this);
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(readframe()));
    connect(Thread1, SIGNAL(finished()), this, SLOT(mshow()));

    Thread0->start();
}

void delay(int msec)
{
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < dieTime )
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

MainWindow::~MainWindow()
{
    if (Thread0) {
          Thread0->quit();
          Thread0->wait();
          delete Thread0;
      }

      if (Thread1) {
          Thread1->quit();
          Thread1->wait();
          delete Thread1;
      }

      if (Thread2) {
          Thread2->quit();
          Thread2->wait();
          delete Thread2;
      }
    delete ui;
}

QImage MainWindow::MattoQt(Mat frame)
{
    Mat temp;
    cvtColor(frame, temp, CV_BGR2RGB);
    QImage src = QImage((uchar*)(temp.data), temp.cols, temp.rows, temp.cols * temp.channels(), QImage::Format_RGB888);
    src = src.scaled(ui->label_11->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
    return src;
}

void MainWindow::readframe()
{
    mycap.read(myframe);
    Thread1->cap1 = mycap;
    Thread1->frame1 = myframe;
    Thread1->start();
    Thread1->wait();

    Thread2->cap2 = mycap;
    Thread2->frame2 = myframe;
    Thread2->start();
    Thread2->wait();
    //delay(500);
    //detfatigue(myframe, ui);
    //mshow();
    QImage img = MattoQt(myframe);
    ui->label_11->setPixmap(QPixmap::fromImage(img));
}

void MainWindow::on_pushButton_clicked()
{
    mycap.open(0);
    //detector = get_frontal_face_detector();
    //deserialize("/opt/QTproject/mDlib/shape_predictor_68_face_landmarks.dat") >> pos_modle;
    timer->start(100);

}

void MainWindow::mshow()
{
    cout<<"2"<<endl;
    //在屏幕上显示眼睛的高度及宽高比
    //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;
            ui->label_3->setText("Eye_Blink:" + QString::number(e_total,10));
            // 重置眼帧计数器
            e_counter = 0;

        }
    }

    if (mnum[0] > MOU_AR_THRESH)
    {

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

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

}

mThread.h

#ifndef NTHREAD_H
#define NTHREAD_H
//#include "dlib.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 <QThread>
#include <opencv2/imgproc/types_c.h>

using namespace dlib;
using namespace cv;

class nThread0 : public QThread
{
public:
    nThread0();
    void run();
};

class nThread1 : public QThread
{
public:
    nThread1();
    void run() ;
signals:
    void finished();
public:
    VideoCapture cap1;
    Mat frame1;
};

class nThread2 : public QThread
{
public:
    nThread2();
    void run() ;
    void detfatigue();
    void detectAndDisplay();
    cv::Mat findSkin (cv::Mat &frame);
    void findEyes(cv::Mat frame, cv::Rect face);

    //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);


signals:
    void finished2();
public:
    VideoCapture cap2;
    Mat frame2;
    nThread1 *sThread;
};


#endif // NTHREAD_H

mThread.cpp

#include "nThread.h"
#include "dlib.h"
#include <QMutex>

using namespace dlib;
using namespace cv;

extern frontal_face_detector detector;
extern shape_predictor pos_modle;
extern float mnum[2];
extern Mat myframe;
extern VideoCapture mycap;

#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/mDlib/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);

nThread0::nThread0()
{

}

void nThread0::run()
{
    QMutex mymutex;
    mymutex.lock();
    detector = get_frontal_face_detector();
    deserialize("/opt/QTproject/mDlib/shape_predictor_68_face_landmarks.dat") >> pos_modle;
    mymutex.unlock();
}

nThread1::nThread1()
{

}

void nThread1::run()
{
    QMutex mutex;
    mutex.lock();
    //cap1.open(0);
    Mat frame;
    //cap1.read(frame1);
    dlib::cv_image<bgr_pixel> cimg(frame1);
    std::vector<dlib::rectangle> faces;
    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]));
    }
    for (int i = 36; i <= 68; i++)
    {       //用来画特征值的点
            cv::circle(frame1, 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;

    //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;

    mutex.unlock();
    emit finished();
    //cout<<"1"<<endl;
}

void nThread1::finished()
{

}

nThread2::nThread2()
{

}

void nThread2::run()
{
    QMutex mutex;
    mutex.lock();
    nThread2::detfatigue();
    cout<<"3"<<endl;
    mutex.unlock();
}

void nThread2::detfatigue()
{
    //sThread->start();
    //sThread->wait();
    cout<<"4"<<endl;
    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(cap2.isOpened() )
          {
            //while( true )
            //{
              //cap2.read(frame2);
              // mirror it
              cv::flip(frame2, frame2, 1);
              frame2.copyTo(debugImage);
              // Apply the classifier to the frame
              if( !frame2.empty() )
              {
                detectAndDisplay();
              }
              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",frame2);
              //}


          }

          releaseCornerKernels();

}

void nThread2::findEyes(cv::Mat frame, cv::Rect face)
{
    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);
       }
}

cv::Mat nThread2::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 nThread2::detectAndDisplay() {
    std::vector<cv::Rect> faces;
    std::vector<cv::Mat> rgbChannels(3);
    cv::split(frame2, 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(frame2, faces[0]);
  }

}

cv::Point nThread2::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 nThread2::scaleToFastSize(const cv::Mat &src,cv::Mat &dst)
{
  cv::resize(src, dst, cv::Size(kFastEyeWidth,(((float)kFastEyeWidth)/src.cols) * src.rows));
}

cv::Mat nThread2::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 nThread2::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 nThread2::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]);
            }
          }
          //-- 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 nThread2::floodShouldPushPoint(const cv::Point &np, const cv::Mat &mat) {
  return inMat(np, mat.rows, mat.cols);
}

cv::Mat nThread2::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; // 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 nThread2::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 nThread2::releaseCornerKernels() {
  delete leftCornerKernel;
  delete rightCornerKernel;
}

// TODO implement these
cv::Mat nThread2::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 nThread2::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 nThread2::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 nThread2::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 nThread2::inMat(cv::Point p,int rows,int cols) {
  return p.x >= 0 && p.x < cols && p.y >= 0 && p.y < rows;
}

cv::Mat nThread2::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 nThread2::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];
}

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值