【OpenCV】OpenCV人脸检测类

来源:互联网 发布:更改ssh 默认端口 编辑:程序博客网 时间:2024/06/03 16:37

源码地址:https://github.com/mc-jesus/face_detect_n_track

1、整张图检测人脸;detectFaceAllSizes

2、人脸区域检测人脸;detectFaceAroundRoi

3、作为模板做模板匹配(跟踪);detectFacesTemplateMatching

#pragma once#include <opencv2\core.hpp>#include <opencv2\highgui\highgui.hpp>#include <opencv2\objdetect\objdetect.hpp>class VideoFaceDetector{public:    VideoFaceDetector(const std::string cascadeFilePath, cv::VideoCapture &videoCapture);    ~VideoFaceDetector();    cv::Point               getFrameAndDetect(cv::Mat &frame);    cv::Point               operator>>(cv::Mat &frame);    void                    setVideoCapture(cv::VideoCapture &videoCapture);    cv::VideoCapture*       videoCapture() const;    void                    setFaceCascade(const std::string cascadeFilePath);    cv::CascadeClassifier*  faceCascade() const;    void                    setResizedWidth(const int width);    int                     resizedWidth() const;    boolisFaceFound() const;    cv::Rect                face() const;    cv::Point               facePosition() const;    void                    setTemplateMatchingMaxDuration(const double s);    double                  templateMatchingMaxDuration() const;private:    static const double     TICK_FREQUENCY;    cv::VideoCapture*       m_videoCapture = NULL;    cv::CascadeClassifier*  m_faceCascade = NULL;    std::vector<cv::Rect>   m_allFaces;    cv::Rect                m_trackedFace;    cv::Rect                m_faceRoi;    cv::Mat                 m_faceTemplate;    cv::Mat                 m_matchingResult;    bool                    m_templateMatchingRunning = false;    int64                   m_templateMatchingStartTime = 0;    int64                   m_templateMatchingCurrentTime = 0;    bool                    m_foundFace = false;    double                  m_scale;    int                     m_resizedWidth = 320;    cv::Point               m_facePosition;    double                  m_templateMatchingMaxDuration = 3;    cv::Rect    doubleRectSize(const cv::Rect &inputRect, const cv::Rect &frameSize) const;    cv::Rect    biggestFace(std::vector<cv::Rect> &faces) const;    cv::Point   centerOfRect(const cv::Rect &rect) const;    cv::Mat     getFaceTemplate(const cv::Mat &frame, cv::Rect face);    void        detectFaceAllSizes(const cv::Mat &frame);    void        detectFaceAroundRoi(const cv::Mat &frame);    void        detectFacesTemplateMatching(const cv::Mat &frame);};


#include "VideoFaceDetector.h"#include <iostream>#include <opencv2\imgproc.hpp>const double VideoFaceDetector::TICK_FREQUENCY = cv::getTickFrequency();VideoFaceDetector::VideoFaceDetector(const std::string cascadeFilePath, cv::VideoCapture &videoCapture){    setFaceCascade(cascadeFilePath);    setVideoCapture(videoCapture);}void VideoFaceDetector::setVideoCapture(cv::VideoCapture &videoCapture){    m_videoCapture = &videoCapture;}cv::VideoCapture *VideoFaceDetector::videoCapture() const{    return m_videoCapture;}void VideoFaceDetector::setFaceCascade(const std::string cascadeFilePath){    if (m_faceCascade == NULL) {        m_faceCascade = new cv::CascadeClassifier(cascadeFilePath);    }    else {        m_faceCascade->load(cascadeFilePath);    }    if (m_faceCascade->empty()) {        std::cerr << "Error creating cascade classifier. Make sure the file" << std::endl            << cascadeFilePath << " exists." << std::endl;    }}cv::CascadeClassifier *VideoFaceDetector::faceCascade() const{    return m_faceCascade;}void VideoFaceDetector::setResizedWidth(const int width){    m_resizedWidth = std::max(width, 1);}int VideoFaceDetector::resizedWidth() const{    return m_resizedWidth;}bool VideoFaceDetector::isFaceFound() const{return m_foundFace;}cv::Rect VideoFaceDetector::face() const{    cv::Rect faceRect = m_trackedFace;    faceRect.x = (int)(faceRect.x / m_scale);    faceRect.y = (int)(faceRect.y / m_scale);    faceRect.width = (int)(faceRect.width / m_scale);    faceRect.height = (int)(faceRect.height / m_scale);    return faceRect;}cv::Point VideoFaceDetector::facePosition() const{    cv::Point facePos;    facePos.x = (int)(m_facePosition.x / m_scale);    facePos.y = (int)(m_facePosition.y / m_scale);    return facePos;}void VideoFaceDetector::setTemplateMatchingMaxDuration(const double s){    m_templateMatchingMaxDuration = s;}double VideoFaceDetector::templateMatchingMaxDuration() const{    return m_templateMatchingMaxDuration;}VideoFaceDetector::~VideoFaceDetector(){    if (m_faceCascade != NULL) {        delete m_faceCascade;    }}cv::Rect VideoFaceDetector::doubleRectSize(const cv::Rect &inputRect, const cv::Rect &frameSize) const{    cv::Rect outputRect;    // Double rect size    outputRect.width = inputRect.width * 2;    outputRect.height = inputRect.height * 2;    // Center rect around original center    outputRect.x = inputRect.x - inputRect.width / 2;    outputRect.y = inputRect.y - inputRect.height / 2;    // Handle edge cases    if (outputRect.x < frameSize.x) {        outputRect.width += outputRect.x;        outputRect.x = frameSize.x;    }    if (outputRect.y < frameSize.y) {        outputRect.height += outputRect.y;        outputRect.y = frameSize.y;    }    if (outputRect.x + outputRect.width > frameSize.width) {        outputRect.width = frameSize.width - outputRect.x;    }    if (outputRect.y + outputRect.height > frameSize.height) {        outputRect.height = frameSize.height - outputRect.y;    }    return outputRect;}cv::Point VideoFaceDetector::centerOfRect(const cv::Rect &rect) const{    return cv::Point(rect.x + rect.width / 2, rect.y + rect.height / 2);}cv::Rect VideoFaceDetector::biggestFace(std::vector<cv::Rect> &faces) const{    assert(!faces.empty());    cv::Rect *biggest = &faces[0];    for (auto &face : faces) {        if (face.area() < biggest->area())            biggest = &face;    }    return *biggest;}/** Face template is small patch in the middle of detected face.*/cv::Mat VideoFaceDetector::getFaceTemplate(const cv::Mat &frame, cv::Rect face){    face.x += face.width / 4;    face.y += face.height / 4;    face.width /= 2;    face.height /= 2;    cv::Mat faceTemplate = frame(face).clone();    return faceTemplate;}void VideoFaceDetector::detectFaceAllSizes(const cv::Mat &frame){    // Minimum face size is 1/5th of screen height    // Maximum face size is 2/3rds of screen height    m_faceCascade->detectMultiScale(frame, m_allFaces, 1.1, 3, 0,        cv::Size(frame.rows / 5, frame.rows / 5),        cv::Size(frame.rows * 2 / 3, frame.rows * 2 / 3));    if (m_allFaces.empty()) return;    m_foundFace = true;    // Locate biggest face    m_trackedFace = biggestFace(m_allFaces);    // Copy face template    m_faceTemplate = getFaceTemplate(frame, m_trackedFace);    // Calculate roi    m_faceRoi = doubleRectSize(m_trackedFace, cv::Rect(0, 0, frame.cols, frame.rows));    // Update face position    m_facePosition = centerOfRect(m_trackedFace);}void VideoFaceDetector::detectFaceAroundRoi(const cv::Mat &frame){    // Detect faces sized +/-20% off biggest face in previous search    m_faceCascade->detectMultiScale(frame(m_faceRoi), m_allFaces, 1.1, 3, 0,        cv::Size(m_trackedFace.width * 8 / 10, m_trackedFace.height * 8 / 10),        cv::Size(m_trackedFace.width * 12 / 10, m_trackedFace.width * 12 / 10));    if (m_allFaces.empty())    {        // Activate template matching if not already started and start timer        m_templateMatchingRunning = true;        if (m_templateMatchingStartTime == 0)            m_templateMatchingStartTime = cv::getTickCount();        return;    }    // Turn off template matching if running and reset timer    m_templateMatchingRunning = false;    m_templateMatchingCurrentTime = m_templateMatchingStartTime = 0;    // Get detected face    m_trackedFace = biggestFace(m_allFaces);    // Add roi offset to face    m_trackedFace.x += m_faceRoi.x;    m_trackedFace.y += m_faceRoi.y;    // Get face template    m_faceTemplate = getFaceTemplate(frame, m_trackedFace);    // Calculate roi    m_faceRoi = doubleRectSize(m_trackedFace, cv::Rect(0, 0, frame.cols, frame.rows));    // Update face position    m_facePosition = centerOfRect(m_trackedFace);}void VideoFaceDetector::detectFacesTemplateMatching(const cv::Mat &frame){    // Calculate duration of template matching    m_templateMatchingCurrentTime = cv::getTickCount();    double duration = (double)(m_templateMatchingCurrentTime - m_templateMatchingStartTime) / TICK_FREQUENCY;    // If template matching lasts for more than 2 seconds face is possibly lost    // so disable it and redetect using cascades    if (duration > m_templateMatchingMaxDuration) {        m_foundFace = false;        m_templateMatchingRunning = false;        m_templateMatchingStartTime = m_templateMatchingCurrentTime = 0;m_facePosition.x = m_facePosition.y = 0;m_trackedFace.x = m_trackedFace.y = m_trackedFace.width = m_trackedFace.height = 0;return;    }// Edge case when face exits frame while if (m_faceTemplate.rows * m_faceTemplate.cols == 0 || m_faceTemplate.rows <= 1 || m_faceTemplate.cols <= 1) {m_foundFace = false;m_templateMatchingRunning = false;m_templateMatchingStartTime = m_templateMatchingCurrentTime = 0;m_facePosition.x = m_facePosition.y = 0;m_trackedFace.x = m_trackedFace.y = m_trackedFace.width = m_trackedFace.height = 0;return;}    // Template matching with last known face     //cv::matchTemplate(frame(m_faceRoi), m_faceTemplate, m_matchingResult, CV_TM_CCOEFF);    cv::matchTemplate(frame(m_faceRoi), m_faceTemplate, m_matchingResult, CV_TM_SQDIFF_NORMED);    cv::normalize(m_matchingResult, m_matchingResult, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());    double min, max;    cv::Point minLoc, maxLoc;    cv::minMaxLoc(m_matchingResult, &min, &max, &minLoc, &maxLoc);    // Add roi offset to face position    minLoc.x += m_faceRoi.x;    minLoc.y += m_faceRoi.y;    // Get detected face    //m_trackedFace = cv::Rect(maxLoc.x, maxLoc.y, m_trackedFace.width, m_trackedFace.height);    m_trackedFace = cv::Rect(minLoc.x, minLoc.y, m_faceTemplate.cols, m_faceTemplate.rows);    m_trackedFace = doubleRectSize(m_trackedFace, cv::Rect(0, 0, frame.cols, frame.rows));    // Get new face template    m_faceTemplate = getFaceTemplate(frame, m_trackedFace);    // Calculate face roi    m_faceRoi = doubleRectSize(m_trackedFace, cv::Rect(0, 0, frame.cols, frame.rows));    // Update face position    m_facePosition = centerOfRect(m_trackedFace);}cv::Point VideoFaceDetector::getFrameAndDetect(cv::Mat &frame){    *m_videoCapture >> frame;    // Downscale frame to m_resizedWidth width - keep aspect ratio    m_scale = (double) std::min(m_resizedWidth, frame.cols) / frame.cols;    cv::Size resizedFrameSize = cv::Size((int)(m_scale*frame.cols), (int)(m_scale*frame.rows));    cv::Mat resizedFrame;    cv::resize(frame, resizedFrame, resizedFrameSize);    if (!m_foundFace)        detectFaceAllSizes(resizedFrame); // Detect using cascades over whole image    else {        detectFaceAroundRoi(resizedFrame); // Detect using cascades only in ROI        if (m_templateMatchingRunning) {            detectFacesTemplateMatching(resizedFrame); // Detect using template matching        }    }    return m_facePosition;}cv::Point VideoFaceDetector::operator>>(cv::Mat &frame){    return this->getFrameAndDetect(frame);}




0 0
原创粉丝点击