《opencv实用探索·二十一》人脸识别

Haar级联分类器
在OpenCV中主要使用了两种特征(即两种方法)进行人脸检测,Haar特征和LBP特征。用的最多的是Haar特征人脸检测。

Haar级联分类器是一种用于目标检测的机器学习方法,它是一种基于机器学习的特征选择方法,能够快速而有效地检测出图像中的对象或特定的模式,例如人脸。
Haar级联分类器工作的基本原理是使用弱分类器(通常是基于决策树的弱分类器)级联成一个强大的分类器。在训练过程中,它通过提取训练样本中的特征并根据这些特征进行分类来逐步学习目标对象(例如人脸)的特征模式。级联的概念允许快速筛选出负样本,减少计算量,从而提高了检测速度。下图展示了级联的过程:
在这里插入图片描述

我们需要考虑如何在层次结构中组合多个Haar级联分类器,以便用一个分类器识别父区域(就目标而言是一张人脸),用其他分类器识别子区域(比如眼睛)。

opencv提供了多种训练好的级联分类器模型文件,这些文件通常是XML格式,存放在opencv安装目录下源码文件夹中sources\data\haarcascades
在这里插入图片描述

haarcascade_eye.xml, 眼睛
haarcascade_eye_tree_eyeglasses.xml, 戴眼镜的眼睛
haarcascade_frontalcatface.xml, 正面猫脸
haarcascade_frontalcatface_extended.xml, 正面猫脸
haarcascade_frontalface_alt.xml, 正面人脸
haarcascade_frontalface_alt2.xml, 正面人脸
haarcascade_frontalface_alt_tree.xml, 正面人脸
haarcascade_frontalface_default.xml, 正面人脸
haarcascade_fullbody.xml, 人体
haarcascade_lefteye_2splits.xml, 左眼
haarcascade_license_plate_rus_16stages.xml,
haarcascade_lowerbody.xml,
haarcascade_profileface.xml,
haarcascade_righteye_2splits.xml, 右眼
haarcascade_russian_plate_number.xml,
haarcascade_smile.xml, 笑脸
haarcascade_upperbody.xml, 上身

从文件名可知这些级联是用于人脸、眼睛、鼻子和嘴的跟踪。这些文件需要正面、直立的人脸图像。创建人脸检测器时会使用这些文件,创建自己的级联,并训练这些级联来检测各种对象。

Haar级联分类器执行流程
1. 数据准备
正样本收集: 收集包含需要检测对象的图像,并对图像进行标注,标注出感兴趣对象的位置。
负样本收集: 收集不包含感兴趣对象的图像,或者与感兴趣对象不相关的图像样本。
创建样本信息文件: 创建包含正样本和负样本信息的数据文件,描述图像路径、对象位置和标签等信息。
2. 特征提取
Haar 特征选择: 对于每个样本图像,从图像中提取 Haar 特征。Haar 特征是一种矩形区域的强度差异计算,用于表示图像的局部特征。
特征值计算: 计算每个样本图像的 Haar 特征值。Haar 特征是根据矩形区域的像素和计算的。这些特征值将用于训练分类器。
3. 训练分类器
级联分类器训练: 使用提取的特征值对分类器进行训练。初始阶段,级联分类器包含多个弱分类器(例如决策树、Adaboost 等)。
特征选择和增强: 训练过程中,级联分类器将对特征进行选择和增强,以提高对感兴趣对象和背景的区分能力。
级联结构构建: 根据训练数据和特征值,构建多个级联阶段,每个阶段都包含多个弱分类器。
4. 级联分类器应用
对象检测: 将训练好的级联分类器应用于新的图像中进行对象检测。级联分类器采用级联结构逐渐缩小搜索区域,使用不同阶段的弱分类器进行对象检测。
非极大值抑制: 对检测到的对象进行非极大值抑制(Non-Maximum Suppression),以消除重叠区域或多次检测到同一对象的情况。

使用 Haar 级联检测器检测图片中的人脸的步骤:
(1)创建一个 CascadeClassifier 级联分类器对象,从 .xml 文件加载级联分类器模型。
(2)读取待检测的图片。
(3)使用 detectMultiScale() 方法检测图片,返回检测到的面部或眼睛的边界矩形。
(4)将检测到的边界矩形绘制到检测图片上。
OpenCV 中定义了级联分类器类 cv::CascadeClassifier。在 Python 语言中,使用接口函数 cv2.CascadeClassifier() 从文件创建分类器。成员函数 cv.CascadeClassifier.detectMultiScale() 用于执行对图像进行目标检测。

代码示例:

#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;


void detectAndDisplay(Mat frame);


//注意,需要把"haarcascade_frontalface_alt.xml"和"haarcascade_eye_tree_eyeglasses.xml"这两个文件复制到工程路径下
string face_cascade_name = "haarcascade_frontalface_alt.xml";
string eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
string window_name = "Capture - Face detection";
RNG rng(12345);

//-----------------------------------【main( )函数】--------------------------------------------
//		描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main(void)
{
    VideoCapture capture;
    Mat frame;

    //-- 1. 加载级联(cascades)
    if (!face_cascade.load(face_cascade_name)) { printf("--(!)Error loading\n"); return -1; };
    if (!eyes_cascade.load(eyes_cascade_name)) { printf("--(!)Error loading\n"); return -1; };

    //-- 2. 读取视频
    capture.open(0);

    if (capture.isOpened())
    {
        for (;;)
        {
            capture >> frame;

            //-- 3. 对当前帧使用分类器(Apply the classifier to the frame)
            if (!frame.empty())
            {
                detectAndDisplay(frame);
            }
            else
            {
                printf(" --(!) No captured frame -- Break!"); break;
            }

            int c = waitKey(10);
            if ((char)c == 'c') { break; }

        }
    }
    return 0;
}


void detectAndDisplay(Mat frame)
{
    std::vector<Rect> faces;
    Mat frame_gray;

    cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
    equalizeHist(frame_gray, frame_gray);

    //-- 人脸检测
   face_cascade.detectMultiScale(frame_gray, faces, 1.1, 3, 0 | CASCADE_SCALE_IMAGE, Size(30, 30),  Size(200, 200));


    for (size_t i = 0; i < faces.size(); i++)
    {
        Point center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2);
        ellipse(frame, center, Size(faces[i].width / 2, faces[i].height / 2), 0, 0, 360, Scalar(255, 0, 255), 2, 8, 0);

        Mat faceROI = frame_gray(faces[i]);
        std::vector<Rect> eyes;

        //-- 在脸中检测眼睛
        eyes_cascade.detectMultiScale(faceROI, eyes, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));

        for (size_t j = 0; j < eyes.size(); j++)
        {
            Point eye_center(faces[i].x + eyes[j].x + eyes[j].width / 2, faces[i].y + eyes[j].y + eyes[j].height / 2);
            int radius = cvRound((eyes[j].width + eyes[j].height) * 0.25);
            circle(frame, eye_center, radius, Scalar(255, 0, 0), 3, 8, 0);
        }
    }
    //-- 显示最终效果图
    imshow(window_name, frame);
}

代码分析:
(1)加载级联分类器
通过 CascadeClassifier 类加载人脸和眼睛的级联分类器(XML 文件),即 haarcascade_frontalface_alt.xml 和 haarcascade_eye_tree_eyeglasses.xml。
(2)读取视频流
使用 VideoCapture 对象打开摄像头设备(ID为0),读取视频帧数据。
(3)循环处理每一帧
在循环中,不断从摄像头捕获帧数据 capture >> frame。
对于每一帧,先进行空帧检测,如果帧不为空则调用 detectAndDisplay() 函数进行人脸和眼睛检测。
(4)人脸检测
detectAndDisplay() 函数将传入的帧 frame 转换为灰度图像 frame_gray,并进行直方图均衡化。
调用 face_cascade.detectMultiScale() 在灰度图像中检测人脸区域,并将检测到的人脸区域存储在 faces 向量中。
什么叫直方图均衡化?
首先直方图是图像中像素强度分布的图形表达方式,它统计了每一个强度值所具有的像素个数。如下图所示,横坐标代表图像的灰度变化0-255,纵坐标代码每个灰度对应的像素个数。
在这里插入图片描述
那么直方图均衡化是通过拉伸像素强度分布范围来增强图像对比度的一种方法。特别是在一些局部对比度较低的图像中,可以帮助提高图像的质量。
说得更清楚一些, 以下面的直方图为例, 你可以看到左边直方图像素主要集中在中间的一些强度值上. 直方图均衡化要做的就是 拉伸 这个范围.。对其应用均衡化后, 得到了右图所示的直方图. 均衡化的图像见下面右图。可以很明显的看到图像对比度得到了增强。
在这里插入图片描述
图像均衡化函数

void equalizeHist(InputArray src, OutputArray dst);

detectMultiScale函数解析:该函数主要用于级联分类器(如 Haar 级联分类器或者基于 HOG 特征的 SVM 分类器)进行对象检测。

void CascadeClassifier::detectMultiScale(
    InputArray image,                        // 输入图像
    std::vector<Rect>& objects,              // 检测到的对象位置矩形
    double scaleFactor = 1.1,                // 每次图像缩小的比例
    int minNeighbors = 3,                    // 最小邻近数,用于合并矩形
    int flags = 0,                           // 未使用的参数,默认为0
    Size minSize = Size(),                   // 对象最小尺寸
    Size maxSize = Size()                    // 对象最大尺寸
);

image:输入图像(灰度图像或彩色图像)。
objects:检测到的对象位置矩形集合,返回给调用者。
scaleFactor:表示在前后两次相继的扫描中,搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10%。建议范围通常在 1.01 到 1.5 之间,较小的值会增加检测时间,但也会增加准确性。较大的值会减少检测时间,但可能会降低准确性。
minNeighbors:匹配成功所需要的周围矩形框的数目,每一个特征匹配到的区域都是一个矩形框,只有多个矩形框同时存在的时候,才认为是匹配成功,比如人脸,这个默认值是3,较大的值可以提高对象检测的准确性,但也会增加漏检率。通常建议设置在3到6之间。
flags:未使用的参数,通常为0。
可以取如下这些值:
CASCADE_DO_CANNY_PRUNING=1, 利用canny边缘检测来排除一些边缘很少或者很多的图像区域
CASCADE_SCALE_IMAGE=2, 正常比例检测
CASCADE_FIND_BIGGEST_OBJECT=4, 只检测最大的物体
CASCADE_DO_ROUGH_SEARCH=8 初略的检测
minSize 和 maxSize:指定对象的最小和最大尺寸。在实际应用中,可以根据目标对象的大小设置这两个参数,以过滤掉尺寸不在指定范围内的检测结果。minSize对于人脸检测,通常设置在 20x20 到 30x30 的范围内。maxSize对于人脸检测,可以设置在 200x200 到 300x300 之间。
(5)眼睛检测
遍历每个检测到的人脸区域,在每个人脸区域中调用 eyes_cascade.detectMultiScale() 进行眼睛检测,并将检测到的眼睛区域存储在 eyes 向量中。
在检测到的每个眼睛区域周围画一个圆圈。
(6)显示结果
最后通过 imshow() 在窗口中显示带有人脸和眼睛检测框的帧图像。

效果显示:
在这里插入图片描述

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【halcon深度学习】create_dl_model_detection

基本介绍 create_dl_model_detection 不是一个封装的库函数&#xff0c;是一个算子。用于创建用于目标检测或实例分割任务的深度学习模型。 输入参数&#xff1a; Backbone (input_control): 指定用作背骨网络的深度学习分类器&#xff0c;充当模型的基础。用户可以选择不同的…

python+pytest接口自动化之测试函数、测试类/测试方法的封装

前言 今天呢&#xff0c;笔者想和大家聊聊pythonpytest接口自动化中将代码进行封装&#xff0c;只有将测试代码进行封装&#xff0c;才能被测试框架识别执行。 例如单个接口的请求代码如下&#xff1a; import requestsheaders {"user-agent": "Mozilla/5.0…

国标28181平台只能连接视频监控吗?

在一些视频监控项目中&#xff0c;国标28181平台成为了必不可少的工具。这个平台的主要作用在于将分布在不同区域的视频监控录像机、摄像头等设备进行联网管理&#xff0c;同时还能将视频监控连接到上一级的国标监控平台。 可以说&#xff0c;国标监控平台是一个非常重要的承上…

【QT】解决QTableView修改合并单元格内容无法修改到合并范围内的单元格

问题:修改合并单元格的内容 修改合并单元格的内容时,希望直接修改到合并范围内的单元格,Qt没有实现这个功能,需要自己写出 Delegate来实现 方案:Delegate class EditDelegate : public QStyledItemDelegate {public:EditDelegate(QTableView *view): tableView(view){}pu…

【Spring Security】让你的项目更加安全的框架

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《MyBatis-Plus》。&#x1f3af;&#x1f3af; &am…

【halcon深度学习之那些封装好的库函数】determine_dl_model_detection_param

determine_dl_model_detection_param 目标检测的数据准备过程中的有一个库函数determine_dl_model_detection_param “determine_dl_model_detection_param” 直译为 “确定深度学习模型检测参数”。 这个过程会自动针对给定数据集估算模型的某些高级参数&#xff0c;强烈建议…

kafka offset sasl加密连接

kafka-tool&#xff08;offset&#xff09; 进行SCRAM连接&#xff0c;直接上图 填写jaas的认证&#xff08;账密 引用包&#xff09;

【Java】网络编程-UDP字典服务器客户端简单代码编写

上文讲了UDP回响服务器客户端简单代码编写 本文将讲述UDP字典服务器客户端简单代码编写。所谓回显&#xff0c;就是指客户端向服务器发送一个报文&#xff0c;从服务器那里得到一条一模一样的回响报文 而我们的字典功能呢&#xff0c;则是实现了输入中文&#xff0c;得到对应…

力扣 面试经典150算法题

1合并两个有序数组88. 合并两个有序数组-CSDN博客简单23

Backend - Django 项目创建 运行

目录 一、配置环境 二、创建 Django 项目 &#xff08;一&#xff09;新建文件夹 &#xff08;二&#xff09;打开文件夹 &#xff08;三&#xff09;打开运行终端 &#xff08;四&#xff09;创建基础项目 &#xff08;五&#xff09;创建app 1. 安装Django &#xf…

分析某款go扫描器之四

一、概述 上文提到实现IP的探测存活以及tcp扫描的实现&#xff0c;这部分来分析实现本机网卡信息获取&#xff0c;以及维护一张mac地址表以及ip扫描端口状态表&#xff0c;同时实现syn扫描功能。 项目来源&#xff1a;https://github.com/XinRoom/go-portScan/blob/main/util…

PY32F072片内闪存读写 HAL库

我这个hal库底层是一次写一页&#xff0c;擦除也是以页为单位的。这个芯片太偏了&#xff0c;有点小恶心。 flash.c uint8_t flash_read(uint32_t add) {uint8_t temp;temp *(__IO uint8_t *)(add);return temp; }void flash_read_buf(uint32_t add, uint8_t *data, uint8_t…

【ICCV 2023】MPI-Flow:什么,只需要单张图片就能训练光流估计模型了?

ICCV 2023 | MPI-Flow&#xff1a;从单视角构建的多平面图像中学习光流 引言&#xff1a;主要贡献&#xff1a;Motivation&#xff1a;算法细节&#xff1a;Optical Flow Data GenerationIndependent Object MotionsDepth-Aware Inpainting 实验结果&#xff1a; 来源&#xff…

Python实现多元线性回归模型信用卡客户价值预测项目源码+数据+项目设计报告

多元线性回归——信用卡客户价值预测 一、背景 这里以信用卡客户的客户价值为例来解释客户价值预测的具体含义&#xff1a; 客户价值预测就是指预测客户在未来一段时间内能带来多少利润&#xff0c;其利润可能来自信用卡的年费、取现手续费、分期手续费、境外交易手续费等。分…

《C++ Primer》第13章 拷贝控制(三)

参考资料&#xff1a; 《C Primer》第5版《C Primer 习题集》第5版 13.5 动态内存管理类&#xff08;P464&#xff09; 某些类需要在运行时分配可变大小的内存空间。这种类通常可以用使用标准库容器来保存它们的数据。有些时候&#xff0c;我们希望类自己进行内存分配&#…

TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)

文章目录 泛型1 泛型2 声明合并 命名空间 模块1 模块2 声明文件简介 泛型1 泛型&#xff08;Generics&#xff09;是指在定义函数、接口或类的时候&#xff0c;不预先指定具体的类型&#xff0c;而在使用的时候再指定类型的一种特性 首先&#xff0c;我们来实现一个函数…

小黑南京归来,参加部里的公务员培训,有点儿社死认识了好多小伙伴的leetcode之旅13. 罗马数字转整数

小黑代码 class Solution:def romanToInt(self, s: str) -> int:chars [M, CM, D, CD, C, XC, L, XL, X, IX, V, IV,I]nums [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]map_ dict((k, v) for k,v in zip(chars, nums))# 字符串长度n len(s)# 结果变量res …

安装Redis+Redis设置成windows下的服务+windows无法启动Redis服务,报错误1067:进程意外终止,解决方法

&#xff08;一&#xff09;安装Redis 官网地址&#xff1a;Redis 不过Redis 的官网不提供 Windows 版本的下载&#xff0c;可以从Github上下载&#xff0c;Windows版本的下载地址&#xff1a; https://github.com/microsoftarchive/redis/releases/ 无需安装&#xff0c;直…

2828. 判别首字母缩略词

2828. 判别首字母缩略词 难度: 简单 来源: 每日一题 2023.12.20 给你一个字符串数组 words 和一个字符串 s &#xff0c;请你判断 s 是不是 words 的 首字母缩略词 。 如果可以按顺序串联 words 中每个字符串的第一个字符形成字符串 s &#xff0c;则认为 s 是 words 的…

比例导引(PNG)-Matlab 程序

本文提供比例导引的matlab程序&#xff0c;想要看理论的可以看书《导弹飞行力学》或者我的博客 比例导引详解 代码 %% 三维比例导引末制导clc;clear; close all;%% 设置导弹初始参数和目标参数% 总步长 length 1000000; x_m zeros(length,1); y_m zeros(length,1); z_m z…