人脸识别(四)

源码位置:https://github.com/comhaqs/face_find.git  分支: develop_face_recognition

opencv的人脸识别模块现在是放在另外一个库opencv_contrib里,需要编译到opencv里才可以使用,故这里将opencv和opencv_contrib的源码都下下来,opencv源码:https://github.com/opencv/opencv/releases ,opencv_contrib源码:https://github.com/opencv/opencv_contrib/releases。两个的版本要一致,例如都是4.2.0。下好后,我这边是使用cmake的gui版本,cmake的源码目录指向opencv的源码目录,输出文件目录最好指向一个空文件夹,然后点击Configure按钮,变量区会有很多红色定义,在变量区中找到OPENCV_EXTRA_MODULES_PATH,将其选择为opencv_contrib/modules目录,并勾选BUILD_opencv_world,再点击configure。直到变量区没有红色,然后点击Generate按钮生成VS项目文件。

生成项目文件后,使用对应的VS打开,然后选择opencv_world工程编译即可,因为是人脸识别,所以还需要将opencv_contrib\modules\face\include下的opencv文件夹合并到程序的include目录里。编译的时候可能会提示部分文件丢失,需要手动下载,官方的issues里有人提到了这个问题(https://github.com/opencv/opencv_contrib/issues/1301),下面有人给出了对应的下载路径。将url显示的内容另存为对应的文件,放到opencv_contrib\modules\xfeatures2d\src目录下即可。其实上面输出文件夹CMakeDownloadLog.txt里已经记录了对应的下载路径。下载时会碰到无法打开url的问题,多刷新几次就可以了。也可以直接从CSDN下载:https://download.csdn.net/download/comhaqs/12088222

Hi! The solution I used was to download by hand all the missing files, so if you encounter the same issue please use the folliwing command in a bash file:

#!/bin/bash
cd ./cache/xfeatures2d/
cd boostdesc

curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_lbgm.i > 0ae0675534aa318d9668f2a179c2a052-boostdesc_lbgm.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_binboost_256.i > e6dcfa9f647779eb1ce446a8d759b6ea-boostdesc_binboost_256.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_binboost_128.i > 98ea99d399965c03d555cef3ea502a0b-boostdesc_binboost_128.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_binboost_064.i > 202e1b3e9fec871b04da31f7f016679f-boostdesc_binboost_064.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_bgm_hd.i > 324426a24fa56ad9c5b8e3e0b3e5303e-boostdesc_bgm_hd.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_bgm_bi.i > 232c966b13651bd0e46a1497b0852191-boostdesc_bgm_bi.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/34e4206aef44d50e6bbcd0ab06354b52e7466d26/boostdesc_bgm.i > 0ea90e7a8f3f7876d450e4149c97c74f-boostdesc_bgm.i
cd ../vgg
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/fccf7cd6a4b12079f73bbfb21745f9babcd4eb1d/vgg_generated_120.i > 151805e03568c9f490a5e3a872777b75-vgg_generated_120.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/fccf7cd6a4b12079f73bbfb21745f9babcd4eb1d/vgg_generated_64.i > 7126a5d9a8884ebca5aea5d63d677225-vgg_generated_64.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/fccf7cd6a4b12079f73bbfb21745f9babcd4eb1d/vgg_generated_48.i > e8d0dcd54d1bcfdc29203d011a797179-vgg_generated_48.i
curl https://raw.githubusercontent.com/opencv/opencv_3rdparty/fccf7cd6a4b12079f73bbfb21745f9babcd4eb1d/vgg_generated_80.i > 7cd47228edec52b6d82f46511af325c5-vgg_generated_80.i

And then run cmake again, and make. Hope this help

 

人脸识别类的代码如下:

#include "face_recognition.h"
#include <opencv2/opencv.hpp>

#include <boost/filesystem.hpp>
#include <boost/format.hpp>

using namespace cv;
using namespace cv::face;

face_recognition::face_recognition()
{

}

void face_recognition::start(){
    try{
        Ptr<LBPHFaceRecognizer> p_model = LBPHFaceRecognizer::create();
        // 获取训练图片集合
        std::vector<info_recognition_ptr> infos;
        if(!find_face_info(infos, "./face")){
            return;
        }
        std::vector<Mat> images;
        std::vector<int> labels;
        for(auto& p_info : infos){
            for(auto& f : p_info->files){
                // 这里记得是IMREAD_GRAYSCALE,即灰度图片,不然会报错
                images.push_back(imread(f, cv::IMREAD_GRAYSCALE));
                labels.push_back(p_info->index);
            }
            m_index_to_name.insert(std::make_pair(p_info->index, p_info->name));
        }
        // 训练模型
        p_model->train(images, labels);
        mp_model = p_model;

        // 加载opencv提供的人脸检测模型,识别率比较低
        std::string face_file("./haarcascade_frontalface_alt2.xml");
        if(boost::filesystem::exists(face_file)){
            mp_cascade = std::make_shared<cv::CascadeClassifier>();
            mp_cascade->load(face_file);
        }else{
            LOG_ERROR("找不到对应的文件检测模型文件:"<<face_file);
        }
    }catch(const std::exception& e){
        LOG_ERROR("发生错误:"<<e.what());
    }
}

bool face_recognition::train(unsigned char *p_data, int width, int height){
    try {
        if(!mp_model || !mp_cascade){
            return false;
        }
        // 原始图片数据转成灰度图片
        cv::Mat bgr(cv::Size(width, height), CV_8UC3);
        bgr.data = p_data;
        cv::Mat gray;
        gray.create(bgr.size(), bgr.type());
        cv::cvtColor(bgr, gray, cv::COLOR_BGR2GRAY);

        // 先人脸检测,再人脸识别
        std::vector<cv::Rect> rect;
        mp_cascade->detectMultiScale(gray, rect, 1.1, 3, 0);
        for (auto& r : rect)
        {
            bool flag_find_face = false;
            std::string name;
            // 复制出检测出来的人脸,然后转换成灰度图片,不转换会报错
            cv::Mat desc;
            bgr(r).copyTo(desc);
            cv::Mat gray_desc;
            gray_desc.create(desc.size(), desc.type());
            cv::cvtColor(desc, gray_desc, cv::COLOR_BGR2GRAY);
            int index = -1;
            double confidence = 0.0;
            // 实际总会返回一个检测结果,置信度暂时不知道怎么使用
            mp_model->predict(gray_desc, index, confidence);
            if(0 > index){

            }else{
                auto iter = m_index_to_name.find(index);
                if(m_index_to_name.end() == iter){
                    LOG_WARN("找不到对应人脸信息;序号:"<<index);
                }else{
                    LOG_INFO("找到人脸;名称:"<<iter->second<<"; 可信度:"<<confidence<<"; 序号:"<<index);
                    name = iter->second;
                    flag_find_face = true;
                }
            }
            if(flag_find_face){
                cv::rectangle(bgr, r, CV_RGB(0, 255, 0), 4);
                cv::putText(bgr, name, Point(r.x + 0.5 * r.width, r.y - 5), cv::FONT_HERSHEY_COMPLEX_SMALL, 1, CV_RGB(0, 255, 0));
            }else{
                cv::rectangle(bgr, r, CV_RGB(255, 0, 0), 2);
            }
        }
    } catch(const std::exception& e){
        LOG_ERROR("发生错误:"<<e.what());
    }

    return true;
}


bool face_recognition::find_and_save_face(const std::string& folder_desc, const std::string& folder_src){
    std::vector<std::string> files;
    if(!find_file_from_folder(files, folder_src)){
        return false;
    }
    cv::CascadeClassifier cascade;
    cascade.load("./haarcascade_frontalface_alt2.xml");
    for(auto& p : files){
        cv::Mat src = cv::imread(p);
        if(nullptr == src.data){
            LOG_ERROR("文件无法正常读取:"<<p);
            continue;
        }
        cv::Mat gray;
        gray.create(src.size(), src.type());
        cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);

        // 人脸检测
        std::vector<cv::Rect> rect;
        cascade.detectMultiScale(gray, rect, 1.1, 3, 0);
        if(rect.empty()){
            LOG_WARN("没有检测到人脸:"<<p);
            continue;
        }
        int index = 0;
        for (auto& r : rect)
        {
            cv::Mat desc;
            src(r).copyTo(desc);
            imwrite((boost::format("%s/%d.png") % folder_desc % (index++)).str(), desc);
        }
    }
    return true;
}
bool face_recognition::find_face_info(std::vector<info_recognition_ptr>& infos, const std::string& folder){
    std::vector<std::string> all_folders;
    if(!find_folder_from_folder(all_folders, boost::filesystem::system_complete(folder).string())){
        return false;
    }
    int index = 1;
    for(auto& d : all_folders){
        std::vector<std::string> files;
        if (!find_file_from_folder(files, d)) {
            continue;
        }
        auto path = boost::filesystem::system_complete(d);
        auto parent_folder = path.parent_path().string();
        auto name = path.string().substr(parent_folder.size() + 1);
        auto p_info = std::make_shared<info_recognition>();
        p_info->index = index++;
        p_info->name = name;
        for(auto& f : files){
            p_info->files.push_back(f);
        }
        infos.push_back(p_info);
    }
    return true;
}

bool face_recognition::find_file_from_folder(std::vector<std::string>& files, const std::string& folder, const std::string& extend){
    boost::filesystem::path path_folder(folder);
    if(!boost::filesystem::exists(path_folder)){
        LOG_ERROR("文件夹路径不存在:"<<folder);
        return false;
    }
    boost::filesystem::directory_iterator end;
    for(boost::filesystem::directory_iterator iter(path_folder); iter != end; ++iter){
        auto path = iter->path();
        if (boost::filesystem::is_directory(path)) {
            continue;
        }
        if(!extend.empty() && extend != path.extension()){
            continue;
        }
        files.push_back(path.string());
    }
    return true;
}

bool face_recognition::find_folder_from_folder(std::vector<std::string>& all_folders, const std::string& folder){
    boost::filesystem::path path_folder(folder);
    if(!boost::filesystem::exists(path_folder)){
        LOG_ERROR("文件夹路径不存在:"<<folder);
        return false;
    }
    boost::filesystem::directory_iterator end;
    for(boost::filesystem::directory_iterator iter(path_folder); iter != end; ++iter){
        auto path = iter->path();
        if (!boost::filesystem::is_directory(path)) {
            continue;
        }
        if("." == path.string() || ".." == path.string()){
            continue;
        }
        all_folders.push_back(path.string());
    }
    return true;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章