使用dlib库和opencv实现人脸检测及识别(C++)

该项目根据官方代码改编。

  1. 准备模型,下载地址
    shape_predictor_5_face_landmarks.dat
    dlib_face_recognition_resnet_model_v1.dat

  2. 创建项目,引入dlib和opencv,CMakeLists.txt代码

cmake_minimum_required(VERSION 2.8)

project(myfaceRecognition)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O2")

IF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything")
ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
ENDIF()

find_package(OpenCV 4.2.0 REQUIRED)

find_package(dlib REQUIRED)
include_directories(${dlib_INCLUDE_DIRS})
add_executable(${PROJECT_NAME} "main.cpp")
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${OpenCV_LIBS} ${dlib_LIBRARIES})
  1. main.cpp 代码
#include <dlib/dnn.h>
#include <dlib/gui_widgets.h>
#include <dlib/clustering.h>
#include <dlib/string.h>
#include <dlib/image_io.h>
#include <dlib/image_transforms.h>
#include <dlib/opencv.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <unistd.h>
#include <dirent.h>
#include <string>
#include <opencv2/opencv.hpp>

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

//神经网络固定模板
template <template <int,template<typename>class,int,typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual = add_prev1<block<N,BN,1,tag1<SUBNET>>>;

template <template <int,template<typename>class,int,typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual_down = add_prev2<avg_pool<2,2,2,2,skip1<tag2<block<N,BN,2,tag1<SUBNET>>>>>>;

template <int N, template <typename> class BN, int stride, typename SUBNET>
using block  = BN<con<N,3,3,1,1,relu<BN<con<N,3,3,stride,stride,SUBNET>>>>>;

template <int N, typename SUBNET> using ares      = relu<residual<block,N,affine,SUBNET>>;
template <int N, typename SUBNET> using ares_down = relu<residual_down<block,N,affine,SUBNET>>;

template <typename SUBNET> using alevel0 = ares_down<256,SUBNET>;
template <typename SUBNET> using alevel1 = ares<256,ares<256,ares_down<256,SUBNET>>>;
template <typename SUBNET> using alevel2 = ares<128,ares<128,ares_down<128,SUBNET>>>;
template <typename SUBNET> using alevel3 = ares<64,ares<64,ares<64,ares_down<64,SUBNET>>>>;
template <typename SUBNET> using alevel4 = ares<32,ares<32,ares<32,SUBNET>>>;

using anet_type = loss_metric<fc_no_bias<128,avg_pool_everything<
                            alevel0<
                            alevel1<
                            alevel2<
                            alevel3<
                            alevel4<
                            max_pool<3,3,2,2,relu<affine<con<32,7,7,2,2,
                            input_rgb_image_sized<150>
                            >>>>>>>>>>>>;

// ----------------------------------------------------------------------------------------

static cv::Rect dlibRectangleToOpenCV(dlib::rectangle r)
{
    return cv::Rect(cv::Point2i(r.left(), r.top()), cv::Point2i(r.right() + 1, r.bottom() + 1));
}
std::vector<string> getFiles(string cate_dir);

int main(int argc, char** argv) try
{
    if (argc != 2)
    {
        cout << "Run this example by invoking it like this: " << endl;
        cout << "   ./myfaceRecognition faces/" << endl;
        cout << endl;
        return 1;
    }

    // 加载人脸检测模型
    frontal_face_detector detector = get_frontal_face_detector();
    // 加载人脸矫正模型
    shape_predictor sp;
    deserialize("shape_predictor_5_face_landmarks.dat") >> sp;
    // 加载人脸编码模型
    anet_type net;
    deserialize("dlib_face_recognition_resnet_model_v1.dat") >> net;

    // 从图片文件夹获取人脸编码
    std::vector<string> filenames = getFiles(argv[1]);
    std::vector<std::pair<matrix<float,0,1>,string>> codeToName;
    for(size_t i = 0; i < filenames.size(); i++)
    {
        matrix<rgb_pixel> img;
        load_image(img, filenames[i]);

        std::vector<matrix<rgb_pixel>> faces;
        for (auto face : detector(img))
        {
            auto shape = sp(img, face);
            matrix<rgb_pixel> face_chip;
            extract_image_chip(img, get_face_chip_details(shape,150,0.25), face_chip);
            faces.push_back(move(face_chip));
        }

        if(faces.size() == 0)
        {
            continue;
        }
        // 编码
        std::vector<matrix<float,0,1>> face_descriptors = net(faces);

		// 提取文件名
        int pos = filenames[i].find_last_of('//');
        string sfilename(filenames[i].substr(pos + 1));

        pos = sfilename.find_last_of('.');
        string sfilenameEx(sfilename.substr(0,pos));

        for(size_t i = 0; i < face_descriptors.size(); i++)
        {
            codeToName.push_back(make_pair(face_descriptors[i],sfilenameEx));
        }
    }

    // 获取相机人脸并对比
    VideoCapture cap;
    cap.open(0);
    cap.set(3,640);
    cap.set(4,480);
    if(!cap.isOpened())
    {
        cout << "camera is open failed!" << endl;
        return -1;
    }

    Mat frame;
    while(cap.read(frame))
    {
        if(frame.empty())
        {
            cout << "image is empty" << endl;
            break;
        }
        flip(frame,frame,1);

        matrix<dlib::rgb_pixel> image;
        dlib::assign_image(image,dlib::cv_image<dlib::rgb_pixel>(frame));

        std::vector<matrix<rgb_pixel>> faces;
        for (auto face : detector(image))
        {
            auto shape = sp(image, face);
            matrix<rgb_pixel> face_chip;
            extract_image_chip(image, get_face_chip_details(shape,150,0.25), face_chip);
            matrix<float,0,1> encode = net(face_chip);
            //faces.push_back(move(face_chip));
            for(size_t j = 0; j < codeToName.size(); j++)
            {
                if (length(encode - codeToName[j].first) < 0.6f)
                {
                    Rect rect = dlibRectangleToOpenCV(face);
                    cv::rectangle(frame,rect.tl(),rect.br(),Scalar(0,255,0),2);
                    cv::putText(frame, codeToName[j].second, cv::Point(rect.tl().x, rect.tl().y - 1), cv::FONT_HERSHEY_PLAIN, 1.2, cv::Scalar(0xFF, 0xFF, 0xFF), 2);
                    break;
                }
            }
        }

        imshow("image",frame);
        if(waitKey(10) == 27)
            break;
    }

    return 0;
}
catch(std::exception& e)
{
    cout << e.what() << endl;
}

std::vector<string> getFiles(string cate_dir)
{
    std::vector<string> files;//存放文件名

    DIR *dir;
    struct dirent *ptr;

    if ((dir=opendir(cate_dir.c_str())) == nullptr)
    {
        perror("Open dir error...");
        exit(1);
    }

    while ((ptr=readdir(dir)) != nullptr)
    {
        if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0)    ///current dir OR parrent dir
            continue;
        if(ptr->d_type == 8)    ///文件夹
        {
            files.push_back(cate_dir + "/" + ptr->d_name);
        }
        else if(ptr->d_type == 4)    ///文件
        {
            std::vector<string> childfiles = getFiles(cate_dir + "/" + ptr->d_name);
            files.insert(files.end(),childfiles.begin(),childfiles.end());
        }
    }
    closedir(dir);

    return files;
}
  1. 编译运行,注意faces文件夹内图片d的命名
mkdir build
cd build & mkdir faces
cmake ..
make
./myfaceRecognition faces/
实现人脸识别,需要使用OpenCVDlib这两个。以下是使用C++实现人脸识别的基本步骤: 1. 安装OpenCVDlib 首先需要安装OpenCVDlib,并将其包含到C++项目中。可以使用以下命令在Ubuntu上安装这两个: ``` sudo apt-get install libopencv-dev sudo apt-get install libdlib-dev ``` 2. 加载人脸识别模型 使用Dlib提供的人脸检测器和68个关键点检测器,需要加载人脸识别模型。可使用以下代码: ``` #include <dlib/opencv.h> #include <dlib/image_processing/frontal_face_detector.h> #include <dlib/image_processing.h> using namespace dlib; frontal_face_detector detector = get_frontal_face_detector(); shape_predictor sp; deserialize("shape_predictor_68_face_landmarks.dat") >> sp; ``` 3. 加载人脸数据 将需要识别的人脸图片保存到人脸数据中。可使用以下代码加载人脸数据: ``` std::vector<matrix<rgb_pixel>> faces; std::vector<std::string> labels; // Load faces from a directory path load_image_dataset(faces, labels, "faces"); ``` 4. 人脸检测和关键点检测 使用Dlib提供的人脸检测器和68个关键点检测器,对待识别的人脸图像进行处理,提取人脸特征。可使用以下代码: ``` // Load the input image cv::Mat inputImg = cv::imread("face.jpg"); // Convert the input image to Dlib's format cv_image<rgb_pixel> dlibImg(inputImg); // Detect faces in the image std::vector<rectangle> dets = detector(dlibImg); // Find the pose of each face std::vector<full_object_detection> shapes; for (unsigned long j = 0; j < dets.size(); ++j) { full_object_detection shape = sp(dlibImg, dets[j]); shapes.push_back(shape); } ``` 5. 人脸识别 将待识别的人脸特征与人脸数据中的特征进行比对,找到最相似的人脸。可使用以下代码: ``` // Compute the face descriptor for each face std::vector<matrix<float,0,1>> faceDescriptors; for (unsigned long i = 0; i < shapes.size(); ++i) { matrix<rgb_pixel> faceChip; extract_image_chip(dlibImg, get_face_chip_details(shapes[i],150,0.25), faceChip); faceDescriptors.push_back(net(faceChip)); } // Find the closest match in the database std::vector<double> distances; std::string bestLabel; double bestDistance = 1.0; for (unsigned long i = 0; i < faces.size(); ++i) { double distance = length(faceDescriptors[0] - faceDescriptors[i]); if (distance < bestDistance) { bestDistance = distance; bestLabel = labels[i]; } } ``` 以上是使用C++实现人脸识别的基本步骤。可以根据实际需求对代码进行修改和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值