opencv进阶 ——(十)图像处理之基于dlib人脸检测与识别

news2024/11/18 23:24:11

        Dlib是一个功能丰富的C++库,设计用于构建复杂的软件系统,尤其在机器学习、计算机视觉和数值计算等领域有着广泛的应用。以下是对Dlib的简要介绍:

  1. 特性

    • 机器学习算法:Dlib包含了各种机器学习算法,如支持向量机(SVMs)、决策树、随机森林、神经网络等。
    • 深度学习框架:Dlib有一个简洁而强大的深度学习接口,允许开发者定义和训练自己的卷积神经网络(CNNs)。
    • 图像处理:提供图像处理和计算机视觉工具,如面部特征检测、物体检测、图像变换等。
    • 数学工具:提供线性代数、优化算法和统计工具,适合数值计算任务。
    • 实用工具:包括日志记录、线程管理、内存管理、序列化等功能。
  2. 文档和示例

    • 全面文档:Dlib的每个类和函数都有详细的文档说明,方便开发者理解和使用。
    • 调试支持:在调试模式下,Dlib提供帮助调试代码的功能,有助于快速定位问题。
    • 示例代码:官方提供许多实例代码,便于学习和参考。
  3. 平台兼容性

    • 跨平台:Dlib可以在Windows、Mac OS和Linux等多种操作系统上编译和运行。
    • 独立性:不依赖于第三方库,易于集成到项目中,编译过程简单。
  4. 开源许可

    • BSD许可证:Dlib采用宽松的BSD许可证,允许在商业和非商业项目中免费使用。
  5. 应用领域

    • 工业界:在机器人、嵌入式设备、移动应用等领域有应用。
    • 学术界:在研究项目中作为强大的工具,用于实验和原型设计。

环境搭建

        源码地址:https://github.com/davisking/dlib

        模型下载:http://dlib.net/files/

人脸检测

        

#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing.h>
#include <dlib/opencv.h>
#include <opencv2/opencv.hpp>

void FaceDetector(cv::Mat& img)
{
    // 加载人脸检测器
    auto detector = dlib::get_frontal_face_detector();

   // 将图片转换为dlib图像格式
    dlib::cv_image<dlib::bgr_pixel> cimg(cvIplImage(img));
 
    // 检测人脸
    std::vector<dlib::rectangle> dets = detector(cimg); 
    std::cout << "number of faces detected:" << dets.size() << std::endl;

}

人脸关键点检测

关键点分布

示例代码

#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include <dlib/opencv.h>

 
using namespace dlib;
using namespace std;
 
int main()
{
    // 加载人脸检测器
    frontal_face_detector detector = get_frontal_face_detector();
 
    // 加载人脸关键点检测器
    shape_predictor sp;
    deserialize("shape_predictor_68_face_landmarks.dat") >> sp;
 
    // 读取图片
    cv::Mat img = cv::imread("image.jpg");
 
    // 将图片转换为dlib图像格式
    cv_image<bgr_pixel> cimg(img);
 
    // 检测人脸
    std::vector<rectangle> faces = detector(cimg);
 
    // 选择最大的人脸
    int max_area = 0;
    rectangle max_face;
    for (int i = 0; i < faces.size(); i++)
    {
        int area = faces[i].area();
        if (area > max_area)
        {
            max_area = area;
            max_face = faces[i];
        }
    }
 
    // 检测关键点
    full_object_detection shape = sp(cimg, max_face);
 

}


人脸识别

参考代码

#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_processing/frontal_face_detector.h>

using namespace dlib;
using namespace std;

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

// The next bit of code defines a ResNet network.  It's basically copied
// and pasted from the dnn_imagenet_ex.cpp example, except we replaced the loss
// layer with loss_metric and made the network somewhat smaller.  Go read the introductory
// dlib DNN examples to learn what all this stuff means.
//
// Also, the dnn_metric_learning_on_images_ex.cpp example shows how to train this network.
// The dlib_face_recognition_resnet_model_v1 model used by this example was trained using
// essentially the code shown in dnn_metric_learning_on_images_ex.cpp except the
// mini-batches were made larger (35x15 instead of 5x5), the iterations without progress
// was set to 10000, and the training dataset consisted of about 3 million images instead of
// 55.  Also, the input layer was locked to images of size 150.
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>
                            >>>>>>>>>>>>;

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

std::vector<matrix<rgb_pixel>> jitter_image(
    const matrix<rgb_pixel>& img
);

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

int main(int argc, char** argv) try
{
    if (argc != 2)
    {
        cout << "Run this example by invoking it like this: " << endl;
        cout << "   ./dnn_face_recognition_ex faces/bald_guys.jpg" << endl;
        cout << endl;
        cout << "You will also need to get the face landmarking model file as well as " << endl;
        cout << "the face recognition model file.  Download and then decompress these files from: " << endl;
        cout << "http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2" << endl;
        cout << "http://dlib.net/files/dlib_face_recognition_resnet_model_v1.dat.bz2" << endl;
        cout << endl;
        return 1;
    }

    // The first thing we are going to do is load all our models.  First, since we need to
    // find faces in the image we will need a face detector:
    frontal_face_detector detector = get_frontal_face_detector();
    // We will also use a face landmarking model to align faces to a standard pose:  (see face_landmark_detection_ex.cpp for an introduction)
    shape_predictor sp;
    deserialize("shape_predictor_5_face_landmarks.dat") >> sp;
    // And finally we load the DNN responsible for face recognition.
    anet_type net;
    deserialize("dlib_face_recognition_resnet_model_v1.dat") >> net;

    matrix<rgb_pixel> img;
    load_image(img, argv[1]);
    // Display the raw image on the screen
    image_window win(img); 

    // Run the face detector on the image of our action heroes, and for each face extract a
    // copy that has been normalized to 150x150 pixels in size and appropriately rotated
    // and centered.
    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));
        // Also put some boxes on the faces so we can see that the detector is finding
        // them.
        win.add_overlay(face);
    }

    if (faces.size() == 0)
    {
        cout << "No faces found in image!" << endl;
        return 1;
    }

    // This call asks the DNN to convert each face image in faces into a 128D vector.
    // In this 128D vector space, images from the same person will be close to each other
    // but vectors from different people will be far apart.  So we can use these vectors to
    // identify if a pair of images are from the same person or from different people.  
    std::vector<matrix<float,0,1>> face_descriptors = net(faces);


    // In particular, one simple thing we can do is face clustering.  This next bit of code
    // creates a graph of connected faces and then uses the Chinese whispers graph clustering
    // algorithm to identify how many people there are and which faces belong to whom.
    std::vector<sample_pair> edges;
    for (size_t i = 0; i < face_descriptors.size(); ++i)
    {
        for (size_t j = i; j < face_descriptors.size(); ++j)
        {
            // Faces are connected in the graph if they are close enough.  Here we check if
            // the distance between two face descriptors is less than 0.6, which is the
            // decision threshold the network was trained to use.  Although you can
            // certainly use any other threshold you find useful.
            if (length(face_descriptors[i]-face_descriptors[j]) < 0.6)
                edges.push_back(sample_pair(i,j));
        }
    }
    std::vector<unsigned long> labels;
    const auto num_clusters = chinese_whispers(edges, labels);
    // This will correctly indicate that there are 4 people in the image.
    cout << "number of people found in the image: "<< num_clusters << endl;


    // Now let's display the face clustering results on the screen.  You will see that it
    // correctly grouped all the faces. 
    std::vector<image_window> win_clusters(num_clusters);
    for (size_t cluster_id = 0; cluster_id < num_clusters; ++cluster_id)
    {
        std::vector<matrix<rgb_pixel>> temp;
        for (size_t j = 0; j < labels.size(); ++j)
        {
            if (cluster_id == labels[j])
                temp.push_back(faces[j]);
        }
        win_clusters[cluster_id].set_title("face cluster " + cast_to_string(cluster_id));
        win_clusters[cluster_id].set_image(tile_images(temp));
    }




    // Finally, let's print one of the face descriptors to the screen.  
    cout << "face descriptor for one face: " << trans(face_descriptors[0]) << endl;

    // It should also be noted that face recognition accuracy can be improved if jittering
    // is used when creating face descriptors.  In particular, to get 99.38% on the LFW
    // benchmark you need to use the jitter_image() routine to compute the descriptors,
    // like so:
    matrix<float,0,1> face_descriptor = mean(mat(net(jitter_image(faces[0]))));
    cout << "jittered face descriptor for one face: " << trans(face_descriptor) << endl;
    // If you use the model without jittering, as we did when clustering the bald guys, it
    // gets an accuracy of 99.13% on the LFW benchmark.  So jittering makes the whole
    // procedure a little more accurate but makes face descriptor calculation slower.


    cout << "hit enter to terminate" << endl;
    cin.get();
}
catch (std::exception& e)
{
    cout << e.what() << endl;
}

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

std::vector<matrix<rgb_pixel>> jitter_image(
    const matrix<rgb_pixel>& img
)
{
    // All this function does is make 100 copies of img, all slightly jittered by being
    // zoomed, rotated, and translated a little bit differently. They are also randomly
    // mirrored left to right.
    thread_local dlib::rand rnd;

    std::vector<matrix<rgb_pixel>> crops; 
    for (int i = 0; i < 100; ++i)
        crops.push_back(jitter_image(img,rnd));

    return crops;
}

其中关键点检测shape_predictor_5_face_landmarks.dat模型也可以改成shape_predictor_68_face_landmarks.dat

人脸识别过程中,需要根据预先录入的人脸信息得到人脸关键点数组

std::vector<matrix<rgb_pixel>> faces;

然后得到人脸描述信息数组

std::vector<matrix<float,0,1>> face_descriptors = net(faces);

同样可以以这种形式得到当前人脸的描述信息,然后去数组中匹配最接近的人脸信息

        length(face_descriptors[i]-face_descriptors[j])

计算人脸描述的差异,值越小标识越接近。

效果展示

人脸检测

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1792026.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java分布式的ACP是什么

ACP 1、ACP是什么 一致性&#xff08;Consistency&#xff09;&#xff1a;在分布式系统中&#xff0c;当更新操作完成之后&#xff0c;所有节点在同一时间看到的数据是一致的。换句话说&#xff0c;对于任何数据的读取&#xff0c;都会得到最后写入的数据。可用性&#xff0…

鸿蒙开发接口安全:【@ohos.userIAM.userAuth (用户认证)】

用户认证 说明&#xff1a; 本模块首批接口从API version 6开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import userIAM_userAuth from ohos.userIAM.userAuth;完整示例 // API version 6 import userIAM_userAuth from ohos.use…

学习笔记——路由网络基础——静态路由(static)

三、静态路由(static) 1、静态路由 (1)定义 静态路由(Static)&#xff1a;由管理员手动配置和维护的路由。静态路由配置简单&#xff0c;被广泛应用于网络中。此外还可以实现负载均衡和路由备份。 静态路由默认优先级为60&#xff0c;如果想在多条静态路由中让某条路由优选…

图片裁剪与上传处理方案 —— 基于阿里云 OSS 处理用户资料

目录 01: 通用组件&#xff1a;input 构建方案分析 02: 通用组件&#xff1a;input 构建方案 03: 构建用户资料基础样式 04: 用户基本资料修改方案 05: 处理不保存时的同步问题 06: 头像修改方案流程分析 07: 通用组件&#xff1a;Dialog 构建方案分析 08: 通用组件&…

宝兰德参编!《2023年中国数据库年度行业分析报告》正式发布

近日&#xff0c;墨天轮发布 《2023年中国数据库年度行业分析报告》&#xff08;以下简称《报告》&#xff09;。宝兰德深度参与《报告》重要章节内容的编写工作&#xff0c;凭借在中间件领域深厚的技术沉淀和丰富的实践经验&#xff0c;输出了大量具有专业性和前瞻性的意见&am…

PHP实现抖音小程序用户登录获取openid

目录 第一步、抖音小程序前端使用tt.login获取code 第二步、前端拿到code传给后端 第三步、方法1 后端获取用户信息 第四步、方法2 抖音小程序拿到用户信息把用户信息传给后端 code2Session抖音小程序用户登录后端文档 第一步、抖音小程序前端使用tt.login获取code 前端 …

如何以抛物线形式排列一个列表,曲线排列 x² = y

如何以抛物线形式排列一个列表&#xff0c;曲线排列 一、需求 做页面的时候遇到一个需求&#xff0c;需要将一个列表以曲线的形式排列展示。 列表内容&#xff1a; const statisticLabels: Array<{name: string,icon: string,path: string,type: string,dataName: strin…

14-alert\confirm\prompt\自定义弹窗

一、认识alert\confirm\prompt 下图依次是alert、confirm、prompt&#xff0c;先认清楚长什么样子&#xff0c;以后遇到了就知道如何操作了。 二、alert操作 先用driver.switch_to.alert方法切换到alert弹出框上&#xff1b;可以用text方法获取弹出的文本信息&#xff1b;acce…

【Qt】定时器播放多张图片,动画效果

1. 效果 2. 代码 2.1 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);~Widget();void initGif(QS…

RPA-UiBot6.0数据采集机器人(海量信息一网打尽)内附RPA师资培训课程

前言 友友们是否曾为海量的数据信息而头疼&#xff0c;不知道如何从中精准抓取你所需的数据&#xff1f;小北的这篇博客将为你揭晓答案&#xff0c;让我们一起学习如何运用RPA数据采集机器人&#xff0c;轻松实现海量信息的快速抓取与整理&#xff0c;助力你的工作效率翻倍&…

用cocos2d-python绘制游戏开发的新篇章

用cocos2d-python绘制游戏开发的新篇章 第一部分&#xff1a;背景 在游戏开发的世界中&#xff0c;寻找一个强大而灵活的框架至关重要。cocos2d-python是一个Python游戏开发框架&#xff0c;它提供了一套丰富的功能&#xff0c;用于创建2D游戏、图形和交互式应用。基于流行的c…

掌握SVG基础:从零开始学习

格栅图可以实现图片的清晰显示&#xff0c;但这也意味着如果要在各种设备上使用格栅图&#xff0c;就会增加大量不同规格的格栅图&#xff0c;以适应各种尺寸的设备。这也直接导致资源文件体积的增加&#xff0c;矢量图没有这个问题。本文将SVG代码编写与即时设计工具相结合&am…

2024050401-重学 Java 设计模式《实战代理模式》

重学 Java 设计模式&#xff1a;实战代理模式「模拟mybatis-spring中定义DAO接口&#xff0c;使用代理类方式操作数据库原理实现场景」 一、前言 难以跨越的瓶颈期&#xff0c;把你拿捏滴死死的&#xff01; 编程开发学习过程中遇到的瓶颈期&#xff0c;往往是由于看不到前进…

[vue2项目]vue2+supermap[mapboxgl]+天地图之地图的初始化

Supermap参考教程 天地图 一、安装 1、终端:npm install supermap/vue-iclient-mapboxgl 2、在package.json文件的dependencies查看supermap/vue-iclient-mapboxgl依赖是否安装成功。 3、在mian.js全局引入 import VueiClient from supermap/vue-iclient-mapboxgl; Vue.use(…

[Classifier-Free] Classifier-Free Diffusion Guidance

1、背景 1&#xff09;Classifier Guidance的问题 a&#xff09;需要额外训练一个分类器&#xff08;要基于噪声图像训练&#xff0c;因此无法用现成的预训练分类器&#xff09;&#xff0c;使得扩散模型的训练pipeline更加复杂 b&#xff09;whether classifier guidance is s…

Vue05-数据绑定

一、数据绑定 1-1、v-bind指令 1-2、v-model指令 1、单项数据绑定&#xff1a; 2、双向数据绑定 注意&#xff1a; 表单元素&#xff0c;必须要有属性&#xff1a;value&#xff01;&#xff01;&#xff01; 1-3、小结

钡铼技术BL103助力实现PLC到OPC-UA无缝转换新高度

在工业4.0的大背景下&#xff0c;信息物理系统和工业物联网的融合日益加深&#xff0c;推动了工业自动化向更高层次的发展。OPC UA作为一种开放、安全、跨平台的通信协议&#xff0c;在实现不同设备、系统间数据交换和互操作性方面扮演了核心角色。钡铼技术公司推出的BL103 PLC…

Java网络编程(上)

White graces&#xff1a;个人主页 &#x1f649;专栏推荐:Java入门知识&#x1f649; &#x1f649; 内容推荐:Java文件IO&#x1f649; &#x1f439;今日诗词:来如春梦几多时&#xff1f;去似朝云无觅处&#x1f439; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微小博主&a…

AI教我变得厉害的思维模式01 - 成长型思维模式

今天和AI一起思考如何培养自己的成长性思维。 一一核对&#xff0c;自己哪里里做到&#xff0c;哪里没有做到&#xff0c;让AI来微调训练我自己。 成长性思维的介绍 成长性思维&#xff08;Growth Mindset&#xff09;是由斯坦福大学心理学教授卡罗尔德韦克&#xff08;Carol…

OpenWrt开启ipv6

原生版本的openwrt, 开启ipv6方法如下&#xff1a; 导航栏 网络->接口 编辑lan接口 DHCP Sever选项里 找到IPv6 Settings 选项&#xff1a; Designated master 不需要开启。RA-Service 设置为 server modeDHCPv6-Service 设置为 server mode 局域网即可确处理IPv6地址分配…