嵌入式人工智能应用-第三章 opencv操作8 图像特征之 Haar 特征

1 Haar 特征

Haar 特征"(Haar Features)是一种在计算机视觉中常用的特征,用于图像识别任务,尤其是在 人脸检测 中非常著名。这个概念最初由 Paul Viola 和 Michael Jones 在 2001 年提出,他们提出的基于 Haar 特征和 AdaBoost 的级联分类器方法实现了非常高效的人脸检测

1.1 背景介绍

Haar-like 特征最早是由 Papageorgiou 等应用于人脸表示,Viola 和 Jones 在此基础上,使用 3 种类型 4种形式的特征。

Haar 特征分为三类:边缘特征、线性特征、中心特征和对角线特征,组合成特征模板。

  1. 边缘特征(Edge Features)
    比如:一个白色矩形和一个相邻的黑色矩形。
    用于检测亮度突然变化的位置,例如眼睛的上下边缘。
    2.线条特征(Line Features):
    比如:白-黑-白 三个矩形排列,用来检测图像中的线条结构。
  2. 中心-周围特征(Center-surround Features):
    比如:中间一个矩形区域和它周围一圈区域做差值,检测人脸中央区域和边缘区域的亮度差异。

特征模板内有白色和黑色两种矩形,并定义该模板的特征值为白 色矩形像素和减去黑色矩形像素和。Haar 特征值反映了图像的灰度变化情况。例如:脸部的一些特征能由矩形特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述特定走向(水平、垂直、对角)的结构。

对于图中的 A, B 和 D 这类特征,特征数值计算公式为:v=Sum 白-Sum 黑,而对于 C 来说,计算公式如下:v=Sum 白-2Sum 黑;之所以将黑色区域像素和乘以 2,是为了使两种矩形区域中像素数目一致。通过改变特征模板的大小和位置,可在图像子窗口中穷举出大量的特征。上图的特征模板称为"特征原型";特征原型在图像子窗口中扩展(平移伸缩)得到的特征称为"矩形特征";矩形特征的值称为"特征值"。
矩形特征可位于图像任意位置,大小也可以任意改变,所以矩形特征值是矩形模版类别、矩形位置和矩形大小这三个因素的函数。故类别、大小和位置的变化,使得很小的检测窗口含有非常多的矩形特征,如:在 24
24 像素大小的检测窗口内矩形特征数量可以达到 16 万个。这样就有两个问题需要解决了:

(1)如何快速计算那么多的特征?积分图

(2)哪些矩形特征才是对分类器分类最有效的?通

过 AdaBoost 算法来训练。积分图就是只遍历一次图像就可以求出图像中所有区域像素和的快速算法,大大的提高了图像特征值计算的效率。积分图主要的思想是将图像从起点开始到各个点所形成的矩形区域像素之和作为一个数组的元素保存在内存中,当要计算某个区域的像素和时可以直接索引 数组的元素,不用重新计算这个区域的像素和,从而加快了计算(这有个相应的称呼,叫做动态规划算法)。积分图能够在多种尺度下,使用相同的时间(常数时 间)来计算不同的特征,因此大大提高了检测速度。

1.2 如何计算 Haar 特征?

1.首先将图像转为灰度。

2.利用 积分图(Integral Image) 快速计算任意矩形区域的像素和。

  1. 将 Haar 特征应用到图像的不同位置和尺度,提取出大量特征。

  2. 使用 AdaBoost 算法 选择最有效的一小部分特征,并训练成一个分类器。

2 Haar 特征

  1. 计算积分图(Integral Image)

  2. 计算 Haar 特征,比如边缘、线条等。

cpp 复制代码
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

// 计算积分图
void computeIntegralImage(const Mat& src, Mat& integralImage) {
    integral(src, integralImage, CV_32S);
}

// 计算 Haar 特征(简单的边缘特征举例)
int computeHaarFeature(const Mat& integralImage, int x, int y, int width, int height) {
    // 假设 Haar 特征是一个横向的边缘特征,计算两个矩形区域的像素和差异
    int topLeft = integralImage.at<int>(y, x);
    int topRight = integralImage.at<int>(y, x + width);
    int bottomLeft = integralImage.at<int>(y + height, x);
    int bottomRight = integralImage.at<int>(y + height, x + width);

    // 计算矩形区域的差异(边缘特征)
    int featureValue = (topLeft + bottomRight) - (topRight + bottomLeft);
    return featureValue;
}

int main() {
    // 加载图像并转换为灰度图
    Mat img = imread("face.jpg", IMREAD_GRAYSCALE);
    if (img.empty()) {
        cout << "Image not found!" << endl;
        return -1;
    }

    // 计算积分图
    Mat integralImg;
    computeIntegralImage(img, integralImg);

    // 计算 Haar 特征(例如边缘特征)
    int x = 50, y = 50; // 特征计算的起始坐标
    int width = 20, height = 10; // 特征矩形区域的宽度和高度

    int haarFeature = computeHaarFeature(integralImg, x, y, width, height);
    cout << "Haar Feature Value: " << haarFeature << endl;

    // 可视化积分图
    Mat visualized;
    normalize(integralImg, visualized, 0, 255, NORM_MINMAX);
    visualized.convertTo(visualized, CV_8U);
    imshow("Integral Image", visualized);

    waitKey(0);
    return 0;
}
  1. 计算积分图:integral() 函数计算出图像的积分图,帮助你快速计算任意矩形区域的像素和。积分图可以让你在常数时间内得到任意矩形区域的和。

  2. 计算 Haar 特征:假设我们计算一个简单的横向边缘特征,即通过两个矩形区域的像素和差异来区分图像中物体的边缘。

  3. 在代码中,computeHaarFeature 计算的是一个简化的 Haar 特征(两个矩形区域差异)。你可以根据需要扩展更多类型的 Haar 特征,如垂直边缘、中心-周围差异等。

  4. 可视化积分图:最后我们用 imshow() 来显示积分图,帮助你理解积分图的效果。

3 人脸检测

3.1 步骤

  1. 创建一个 Haar 级联分类器对象
  2. 加载 OpenCV 提供的人脸检测模型文件(基于 Haar 特征训练的 XML)
  3. 把彩色图像 frame 转为灰度图,因为 Haar 特征只需要灰度,不处理颜色。

3.2 函数介绍

cpp 复制代码
face_cascade.detectMultiScale(
    frame_gray,   // 输入图像
    faces,        // 输出检测到的人脸位置
    1.1,          // 缩放比例(每次图像缩小的比例)
    4,            // 最小邻近框数(越大越严格)
    0,            // 标志位,一般为0
    Size(30,30)   // 最小检测窗口大小
);

3.3 具体代码实现

cpp 复制代码
		CascadeClassifier face_cascade;                                                                                                                
 57     face_cascade.load("//usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml");
 58 
 59     Mat frame = imread(argv[1]);
 60     if (frame.empty()) {
 61         cout << "Image not found!" << endl;
 62         return -1;
 63     }
 64 
 65     Mat frame_gray;
 66     cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
 67     equalizeHist(frame_gray, frame_gray);  // 🌟 提高对比度(可选,但提升检测准确率)
 68 
 69     vector<Rect> faces;
 70     face_cascade.detectMultiScale(frame_gray, faces, 1.1, 4, 0, Size(30, 30));
 71 
 72     for (size_t i = 0; i < faces.size(); i++) {
 73         rectangle(frame, faces[i], Scalar(255, 0, 0), 2);
 74     }
 75 
 76     imshow("Detected Faces", frame);
 77     waitKey(0);
 78     return 0; 
 79     waitKey(0);
 80     return 0;

4 特点

✅ 优点

非常快,适合实时应用。

对亮度变化不敏感。

❌ 缺点

对复杂背景或光照变化不太鲁棒。

相比于深度学习方法,准确率较低。

相关推荐
IT_陈寒1 小时前
Vue这个坑我跳了两次,原来问题出在这
前端·人工智能·后端
新新技术迷2 小时前
Node给AI接口做SSE代理与鉴权
人工智能
redreamSo3 小时前
大模型是不是到顶了?瓶颈到底在哪
人工智能·openai
Oo9203 小时前
Tool Use 背后的技术逻辑
人工智能
姗姗来迟了3 小时前
Vue3封装AI流式对话组件踩坑实录
人工智能
码上天下3 小时前
用Pinia管理AI多会话状态
人工智能
用户054324329704 小时前
Next.js接大模型流式SSE实操踩坑
人工智能
Assby4 小时前
从 Function Calling 到 MCP:理解 Agent 工具调用的底层通信机制
人工智能·后端
小星AI4 小时前
Claude Code 从入门到精通,一步到位
人工智能
后端小肥肠5 小时前
Codex + Obsidian 做人生副本视频:输入主题文案,直通剪映草稿
人工智能·aigc·agent