《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, // 未使用的参数,默认为0Size 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() 在窗口中显示带有人脸和眼睛检测框的帧图像。
效果显示:


相关文章:
《opencv实用探索·二十一》人脸识别
Haar级联分类器 在OpenCV中主要使用了两种特征(即两种方法)进行人脸检测,Haar特征和LBP特征。用的最多的是Haar特征人脸检测。 Haar级联分类器是一种用于目标检测的机器学习方法,它是一种基于机器学习的特征选择方法,…...
前端项目配置下载源npm, yarn,pnpm
前端项目配置下载源 npm: npm config set registry registryhttps://registry.npmmirror.com -g验证: npm config get registry yarn: yarn config set registry registryhttps://registry.npmmirror.com -gyarn config get registryyarn找不到, 需要管理员在命令行: set-exec…...
Elasticsearch之ik中文分词篇
Elasticsearch之ik中文分词篇 ik分词器插件ik分词器安装ik分词模式es ik分词测试 ik分词器插件 es在7.3版本已经支持中文分词,由于中文分词只能支持到单个字进行分词,不够灵活与适配我们平常使用习惯,所以有很多对应中文分词出现,…...
2023_Spark_实验三十:测试Flume到Kafka
实验目的:测试Flume采集数据发送到Kafka 实验方法:通过centos7集群测试,将flume采集的数据放到kafka中 实验步骤: 一、 kafka可视化工具介绍 Kafka Tool是一个用于管理和使用Apache Kafka集群的GUI应用程序。 Kafka Tool提供了…...
urllib2 HTTP头部注入
文章目录 注入原理例题 [SWPU 2016]web7 注入原理 参考文章 应用场景是具有SSRF漏洞,结合CRLF注入 我们以redis数据库为例,当存在SSRF时我们伪造以下请求 http://127.0.0.1%0d%0aCONFIG%20SET%20dir%20%2ftmp%0d%0aCONFIG%20SET%20dbfilename%20evil%…...
在 WebRTC 中,Offer/Answer 模型是协商 WebRTC 连接参数的关键部分
在 WebRTC 中,Offer/Answer 模型是协商 WebRTC 连接参数的关键部分。当 Offer 和 Answer 交换失败时,可能涉及到多个原因。以下是一些可能的问题和解决方案: SDP 格式错误: Session Description Protocol(SDPÿ…...
数据结构:图解手撕B-树以及B树的优化和索引
文章目录 为什么需要引入B-树?B树是什么?B树的插入分析B树和B*树B树B*树分裂原理 B树的应用 本篇总结的内容是B-树 为什么需要引入B-树? 回忆一下前面的搜索结构,有哈希,红黑树,二分…等很多的搜索结构&a…...
useConsole的封装,vue,react,htmlscript标签,通用
之前用了接近hack的方式实现了console的封装,目标是获取console.log函数的执行(调用栈所在位置)所在的代码行数。 例如以下代码,执行window.mylog(1)时候,console.log实际是在匿名的箭头函数()>{//这里执行的} con…...
Azure Machine Learning - 提示工程高级技术
本指南将指导你提示设计和提示工程方面的一些高级技术。 关注TechLead,分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,…...
七款创意项目管理软件解决方案推荐:高效项目管理与团队协作工具
企业无论大小,都离不开项目经理、营销团队和创意人员。他们参与各种头脑风暴,为特定目标打造项目。然而,在创意项目管理中,细节决定成败。若处理不当,可能导致项目失败和混乱。 过去,创意项目管理依赖纸质规…...
如何在公网环境下使用Potplayer访问本地群晖webdav中的影视资源
文章目录 本教程解决的问题是:按照本教程方法操作后,达到的效果是:1 使用环境要求:2 配置webdav3 测试局域网使用potplayer访问webdav3 内网穿透,映射至公网4 使用固定地址在potplayer访问webdav 国内流媒体平台的内…...
数据可视化Seaborn
数据可视化Seaborn Seaborn简介Seaborn API第一个Seaborn应用Seaborn基本概念Seaborn图表类型Seaborn数据集Seaborn样式Seaborn调色板Seaborn分面网格Seaborn统计图表Seaborn散点图Seaborn折线图Seaborn柱状图Seaborn箱线图Seaborn核密度估计图Seaborn分类散点图Seaborn回归分…...
AWS S3相关配置笔记
关闭 阻止所有公开访问 存储桶策略(开放外部访问) {"Version": "2012-10-17","Id": "S3PolicyId1","Statement": [{"Sid": "statement1","Effect": "Allow","Principal"…...
linux:linux的小动物们(ubuntu)
1.蒸汽小火车 输入下面的命令下载,再输出sl sudo apt-get install sl sl2.今天你哞了吗 apt-get moo 3.会说话的小牛 输入下面的命令下载一下 sudo apt-get install cowsay输入这个 cowsay jianbing cowsay -l 查看其它动物的名字 然后cowsay -f 跟上动物名&…...
每日一题(LeetCode)----栈和队列--逆波兰表达式求值
每日一题(LeetCode)----栈和队列–逆波兰表达式求值 1.题目(150. 逆波兰表达式求值) 给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意: 有效的算…...
2023年第四届 “赣网杯” 网络安全大赛 gwb-web3 Write UP【PHP 临时函数名特性 + 绕过trim函数】
一、题目如下: 二、代码解读: 这段代码是一个简单的PHP脚本,它接受通过GET请求传递的两个参数:‘pass’和’func’: ① $password trim($_GET[pass] ?? );:从GET请求中获取名为’pass’的参数࿰…...
软件设计师——软件工程(一)
📑前言 本文主要是【软件工程】——软件设计师——软件工程的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 🌄…...
阿里云|人工智能(AI)技术解决方案
函数计算部署Stable Diffusion AI绘画技术解决方案 通过函数计算快速部署Stable Diffusion模型为用户提供快速通过文字生成图片的能力。该方案通过函数计算快速搭建了AIGC的能力,无需管理服务器等基础设施,专注模型的能力即可。该方案具有高效免运维、弹…...
Axure中继器的使用
一.中继器介绍 在Axure中,中继器(Relays)是一种功能强大的元件,可以用于创建可重复使用的模板或组件。中继器允许您定义一个主要的模板,并在页面中重复使用该模板的实例。以下是中继器的作用和优缺点: 作…...
猫罐头哪个牌子好性价比高?五大性价比高的品牌推荐
很多猫奴担心猫咪天天吃干猫粮可能会导致营养不足,所以想给猫咪换换口味,改善一下饮食。这时,选择猫罐头是个不错的选择。不过,喂猫罐头也是有一些讲究的。 作为从业6年的宠物护理师来说,作为早在几年就开始接触猫罐头…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
