简介
CascadeClassifier
是 OpenCV 库中的一个关键组件,主要用于对象检测,特别是面部检测和其他特征点的检测。这个类实现了一种基于级联分类器的算法,该算法最初由 Paul Viola 和 Michael Jones 在他们的论文《Rapid Object Detection using a Boosted Cascade of Simple Features》中提出。以下是 CascadeClassifier
的一些核心特性与功能的介绍:
-
级联分类器结构:
- 级联分类器是由一系列弱分类器(如 Haar 特征或 Local Binary Patterns (LBP) 特征)组成的强分类器。每个弱分类器逐步过滤掉非目标区域,减少误检率,同时尽可能保持高召回率。
-
训练过程:
- 训练级联分类器通常涉及大量正样本(包含目标的图像)和负样本(不包含目标的图像)。OpenCV 提供了
opencv_traincascade
工具来训练自定义的级联分类器,该工具会使用 AdaBoost 算法来选择最优特征并构建级联结构。
- 训练级联分类器通常涉及大量正样本(包含目标的图像)和负样本(不包含目标的图像)。OpenCV 提供了
-
检测过程:
- 使用
detectMultiScale()
函数可以在给定的图像中检测目标。这个函数可以处理多个尺度和旋转,以检测不同大小和方向的目标。
- 使用
-
函数说明:
CascadeClassifier()
:构造函数,用于初始化分类器。load(filename)
:从文件加载级联分类器模型。empty()
:检查分类器是否已加载。read(node)
:从FileStorage
节点读取分类器配置。
-
效率:
- 级联分类器设计得非常高效,因为它能够在早期阶段快速排除大部分非目标区域,减少了后续计算的需求。
-
应用场景:
- 除了人脸识别,还可以用于眼睛、行人、车辆等其他物体的检测。
-
局限性:
- 级联分类器可能对光照变化、遮挡和姿态变化敏感。
- 训练过程可能需要大量的计算资源和时间。
- 对于复杂场景和多类目标检测,现代深度学习方法(如 YOLO, SSD, 或者 Faster R-CNN)通常表现更优。
支持的特征
opencv目前仅支持三种特征的训练检测, HAAR、LBP、HOG。
Haar特征
-
基本概念:
- Haar特征是基于矩形结构的简单特征,这些矩形可以是相同大小或不同大小,可以是并排放置、重叠或堆叠。它们通过比较不同矩形区域内像素的平均灰度值来捕捉图像中的局部强度变化。
-
特征类型:
- 边缘特征:包含两个相同宽度但不同高度的矩形,比较顶部和底部矩形的像素和。
- 线性特征:涉及两个相邻的矩形,水平或垂直放置,比较它们的像素和。
- 中心特征:一个大的矩形被一个小的矩形分割,比较两部分的像素和。
- 对角线特征:矩形沿着对角线方向放置,比较对角线两边的像素和。
-
特征模板:
- Haar特征的模板由黑矩形和白矩形组成,它们可以是连续的或间隔的。特征值是白色矩形像素和减去黑色矩形像素和。
-
优势:
- 快速计算:Haar特征可以快速计算,适合实时处理。
- 简单表示:易于编程和理解。
- 适应性强:能够检测到图像中的一些基本形状和强度变化,如边缘和局部对比度。
-
级联分类器:
- Haar特征与级联分类器结合使用,形成一系列的弱分类器,这些弱分类器串联起来,逐步过滤图像区域,最终找到目标对象。
-
局限性:
- Haar特征对复杂形状和纹理的描述能力有限。
- 容易受到光照、遮挡和噪声的影响。
- 需要大量的训练数据和计算资源来训练级联分类器。
LBP 特征
局部二值模式(Local Binary Pattern, LBP)是一种在计算机视觉和图像处理领域广泛应用的纹理描述符,主要用于纹理分类和图像分析。以下是 LBP 的详细介绍:
-
基本原理:
- LBP 通过比较中心像素点与周围像素点的灰度值,将比较结果转换为二进制数,形成一个二进制码,以此来表征图像局部区域的纹理信息。
- 常见的 LBP 算子考虑的是像素点周围的 8 邻域(即一个 3x3 窗口,中心是待分析像素)。
-
计算过程:
- 对于图像中的每个像素 (P_c),选取其周围的 (P_1) 到 (P_8) 共8个像素(以顺时针或逆时针顺序)。
- 比较每个邻域像素 (P_i) 与中心像素 (P_c) 的灰度值,如果 (P_i >= P_c),则记为1,否则记为0。
- 将这8个比较结果拼接起来,形成一个8位的二进制数,这个数就是该像素位置的 LBP 码。
- 进一步地,可以将这个二进制数转换为十进制数,作为该像素的一个标签。
-
改进与扩展:
- 圆形LBP:为了提高旋转不变性,可以采用圆形邻域而非传统的矩形邻域,选择不同半径和不同数量的采样点。
- 统一模式(Uniform LBP):由于原始LBP码的数量随着邻域大小的增加而迅速增长,统一模式仅保留那些“变化次数”较少的模式,简化了特征空间。
- 旋转不变LBP:通过对LBP码进行循环移位操作找到最小的等效码,实现旋转不变性。
-
应用:
- 纹理分类:LBP 算子因其简单高效而成为纹理分类任务的首选方法之一。
- 人脸识别:结合其他特征或直接作为特征用于人脸图像的识别。
- 对象检测:在一些场景下,LBP 可以作为特征描述符用于目标检测。
- 图像分割:基于纹理特征的图像分割任务。
-
优势:
- 计算简单快速,对光照变化具有一定的鲁棒性。
- 可以在不同尺度上进行分析,适应性强。
- 易于构建直方图特征,便于后续的统计分析和机器学习。
HOG特征
Histogram of Oriented Gradients (HOG) 是一种计算机视觉特征提取方法,常用于行人检测和物体识别。以下是 HOG 的详细介绍:
-
基本原理:
- HOG 模型通过计算和积累图像中每个像素邻域内的梯度方向直方图来描述图像局部结构。
- 它捕捉图像中边缘和形状信息,这些信息对于识别和分类任务至关重要。
-
步骤:
- 梯度计算:对图像进行灰度处理,然后计算每个像素的强度梯度(幅度和方向)。
- 细胞单元(Cell)定义:将图像划分为小的正方形区域(例如8x8像素)称为细胞单元。
- 梯度直方图:在每个细胞单元内,根据梯度方向创建一个直方图。通常使用9个或16个 bin,对应不同的角度范围。
- 块定义:多个相邻的细胞组成一个更大的块(例如2x2细胞)。
- 重归化(Normalization):在每个块内进行局部对比度归一化,以减少光照变化的影响。
- 构造特征向量:将所有块的直方图组合成一个特征向量,形成整个图像的 HOG 描述符。
-
应用:
- 行人检测:HOG 是最著名的行人检测算法之一,因为它对人的轮廓和姿态变化有较好的鲁棒性。
- 物体识别:除了行人检测,HOG 也被广泛应用于其他物体识别任务,如车辆、面部等。
- 计算机视觉:HOG 特征与机器学习算法(如支持向量机 SVM)结合,用于图像分类和目标检测。
-
优缺点:
- 优点:对形变和遮挡有一定的鲁棒性,计算相对高效。
- 缺点:对光照变化敏感,可能需要预处理步骤来减小影响。对于非刚性变形或复杂背景的物体,性能可能会下降。
-
相关库:
- 在 OpenCV 库中,提供了
cv::HOGDescriptor
类来方便地实现 HOG 特征的计算。
- 在 OpenCV 库中,提供了
实战
detectMultiScale函数详解
detectMultiScale
函数是 OpenCV 库中用于对象检测的关键函数,特别是对于基于级联分类器(如 Haar 特征或 LBP 特征)的对象检测。这个函数通常用于检测像人脸、眼睛、车辆等这样的固定形状或特征的对象。以下是对 detectMultiScale
函数的详细介绍:
void detectMultiScale(
InputArray image,
OutputArray objects,
double scaleFactor = 1.1,
int minNeighbors = 3,
int flags = 0,
Size minSize = Size(),
Size maxSize = Size()
);
参数说明如下:
image
:输入图像,通常是灰度图像。objects
:输出结果,一个std::vector<Rect>
类型,包含了检测到的所有对象的边界框。scaleFactor
:缩放因子,用于在不同尺度上搜索对象。每轮迭代,图像会按此比例缩小或放大,以检测不同大小的对象。minNeighbors
:连接组件的最小邻居数量,用于确定一个检测窗口是否属于有效对象。如果一个检测窗口周围有至少minNeighbors
个相似的窗口,那么它被认为是有效的。flags
:标志位,可以包含CASCADE_SCALE_IMAGE
(对输入图像进行缩放)和其他选项,具体取决于应用场景。minSize
:最小对象尺寸,小于这个尺寸的对象将被忽略。maxSize
(可选):最大对象尺寸,大于这个尺寸的对象将被忽略。
这个函数通常与预先训练好的级联分类器(如 XML 文件)一起使用,例如 Haar 特征级联分类器,用于检测图像中的人脸或其他特征。级联分类器是由多个弱分类器组成的强分类器,它们逐级过滤图像中的候选区域,以减少误检并提高检测速度。
例如,如果你有一个预训练的人脸检测 Haar 级联分类器,你可以这样调用 detectMultiScale
函数:
#include <opencv2/objdetect.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
int main() {
CascadeClassifier face_cascade;
face_cascade.load("path_to_your_haar_cascade_xml_file.xml");
Mat img = imread("path_to_your_input_image.jpg", IMREAD_GRAYSCALE);
if (img.empty()) {
std::cout << "Error: Could not load image." << std::endl;
return -1;
}
std::vector<Rect> faces;
face_cascade.detectMultiScale(img, faces, 1.1, 4);
for (size_t i = 0; i < faces.size(); i++) {
rectangle(img, faces[i], Scalar(255, 0, 0), 2);
}
imshow("Detected Faces", img);
waitKey(0);
return 0;
}
更多分类器xml文件:https://github.com/opencv/opencv/tree/master/data/haarcascades