基于OpenCV的Haar与LBP级联分类器

级联分类器原理-AdaBoost

 ·Viola和Jones – 2001在CVPR提出  

        ·一种实时对象(人脸)检测框架  

        ·训练速度非常慢,检测速度非常快

        ·5000个正向人脸样本与300万个非人脸负样本数据

  • 弱分类器-Weak classifier = Feature
  • 强分类器-多个弱分类器的线性组合
  • 级联分类器-多个强分类器的组合

在这里插入图片描述

       Boosting算法是一种通过多次学习来提升算法精度的方法,它采用的是综合的原则使得算法的效率明显改善,是一种将弱分类器提升为强分类器的方法,AdaBoost算法是一种自适应Boosting算法,自适应在于将前一个分类器分错的样本会被用来训练下一个分类器,这种方法是一种迭代算法,在每一轮中加入一个新的弱分类器,直到达到某个预定的足够小的错误率。每一个训练样本都被赋予一个权重,表明它被某个分类器选入训练集的概率。如果某个样本点已经被准确地分类,那么在构造下一个训练集中,它被选中的概率就被降低;相反,如果某个样本点没有被准确地分类,那么它的权重就得到提高。通过这样的方式,AdaBoost方法能“聚焦于”那些较难分(更富信息)的样本上。

       Adaboost算法基本原理就是将多个弱分类器(弱分类器一般选用单层决策树)进行合理的结合,使其成为一个强分类器。Adaboost采用迭代的思想,每次迭代只训练一个弱分类器,训练好的弱分类器将参与下一次迭代的使用。也就是说,在第N次迭代中,一共就有N个弱分类器,其中N-1个是以前训练好的,其各种参数都不再改变,本次训练第N个分类器。其中弱分类器的关系是第N个弱分类器更可能分对前N-1个弱分类器没分对的数据,最终分类输出要看这N个分类器的综合效果。
        最新的训练和检测代码实现了Haar、LBP和HOG特征接口,同时训练代码中支持DAB、LAB、RAB和GAB共4种Adaboost算法,另外还实现了trim weight方法。

HAAR与LBP区别

  • HAAR特征是浮点数运算
  • LBP特征是整数计算
  • LBP训练需要的样本数量要比HAAR大
  • 同样的样本训练空间,HAAR训练出来的数据检测结果要比LBP准确
  • 扩大LBP的样本数据,训练结果可以跟HAAR一样
  • LBP的速度一般比HAAR快几倍

Haar特征:OpenCV——Haar特征_DDsoup的博客-CSDN博客

LBP特征:OpenCV——LBP特征_DDsoup的博客-CSDN博客

Adaboost 训练过程

  

Adaboost 分类过程

       可以看到通过级联Adaboost分类器们能够使用较少的特征和较简单的分类器更快更好的实现分类。另外在检测的过程中,因为TPR较高,所以一旦检测到某区域不是目标就可以直接停止后续检测,这样大部分检测窗口都能够很快停止,分类速度得到很大的提高。

       TPR(True Positive Rate)可以理解为所有正类中,有多少被预测成正类(正类预测正确),即召回率,给出定义如下:

\large TPR=\frac{TP}{TP+FN}

API

       它可以检测出图片中所有的人脸,并将人脸用vector保存各个人脸的坐标、大小(用矩形表示),函数由分类器对象调用.

void CascadeClassifier::detectMultiScale( 	
                                        InputArrayimage,
		                                vector< Rect > &  	objects,
		                                double scaleFactor = 1.1,
		                                int minNeighbors = 3,
		                                int flags = 0,
		                                Size minSize = Size(),
	                                	Size maxSize = Size() 
	                                     ); 	

参数说明

1) image 表示的是要检测的输入图像
2) objects 表示检测到的人脸目标序列
3) scaleFactor 表示每次图像尺寸减小的比例
4) minNeighbors 表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗      口大小都可以检测到人脸),
5) minSize 为目标的最小尺寸
6) maxSize 为目标的最大尺寸

代码示例(摄像头版)

#include<iostream>
#include<opencv2/opencv.hpp>
#include<librealsense2/rs.hpp>
#include <librealsense2/h/rs_option.h>
#include "example.hpp" 
using namespace std;
using namespace cv;
using namespace rs2;
Mat Facejudge(Mat color_image)
{
	Mat gray;
	cvtColor(color_image, gray, COLOR_BGR2GRAY);
	equalizeHist(gray, gray);

	vector<Rect> faces;
	vector<Rect> eyes;
	Rect rect;
	Mat faceROI;
	CascadeClassifier face_classifier;
	CascadeClassifier eye_classifier;

	face_classifier.detectMultiScale(gray, faces, 1.2, 3, 0, Size(30, 30));
	for (size_t t = 0; t < faces.size(); t++)
	{
		faceROI = color_image(faces[static_cast<int>(t)]);
		eye_classifier.detectMultiScale(faceROI, eyes, 1.2, 3, 0, Size(10, 10));
		for (size_t k = 0; k < eyes.size(); k++)
		{
			rect.x = faces[static_cast<int>(t)].x + eyes[k].x;
			rect.y = faces[static_cast<int>(t)].y + eyes[k].y;
			rect.width = eyes[k].width;
			rect.height = eyes[k].height;
			rectangle(color_image, rect, Scalar(0, 255, 0), 2, 8, 0);
		}
		rectangle(color_image, faces[static_cast<int>(t)], Scalar(0, 0, 255), 2, 8, 0);
	}
	return color_image;
}

int main()
{
	colorizer color_map;
	pipeline pipe;
	pipe.start();
	const auto window_name = "Display color_Image";
	namedWindow(window_name, WINDOW_AUTOSIZE);
	while (waitKey(1) < 0 && getWindowProperty(window_name, WND_PROP_AUTOSIZE) >= 0)
	{
		frameset data = pipe.wait_for_frames();    // 等待下一帧
		frame frames = data.get_color_frame()
		  .apply_filter(color_map);

		const int w = frames.as<video_frame>().get_width();
		const int h = frames.as<video_frame>().get_height();

		// 由rs2::frame转为cv::Mat
		Mat color_image(Size(w, h), CV_8UC3, (void*)frames.get_data(), Mat::AUTO_STEP);
	
		color_image = Facejudge(color_image);
		imshow(window_name, color_image);
	}
	return 0;
}

代码演示(图片版)

#include<iostream>
#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

Mat Facejudge(Mat color_image)
{
    Mat gray;
    cvtColor(color_image, gray, COLOR_BGR2GRAY);
    equalizeHist(gray, gray);

    vector<Rect> faces;
    vector<Rect> eyes;
    Rect rect;
    Mat faceROI;
    CascadeClassifier face_classifier;
    CascadeClassifier eye_classifier;

    face_classifier.detectMultiScale(gray, faces, 1.2, 3, 0, Size(30, 30));
    for (size_t t = 0; t < faces.size(); t++)
    {
        faceROI = color_image(faces[static_cast<int>(t)]);
        eye_classifier.detectMultiScale(faceROI, eyes, 1.2, 3, 0, Size(10, 10));
        for (size_t k = 0; k < eyes.size(); k++)
        {
            rect.x = faces[static_cast<int>(t)].x + eyes[k].x;
            rect.y = faces[static_cast<int>(t)].y + eyes[k].y;
            rect.width = eyes[k].width;
            rect.height = eyes[k].height;
            rectangle(color_image, rect, Scalar(0, 255, 0), 2, 8, 0);
        }
        rectangle(color_image, faces[static_cast<int>(t)], Scalar(0, 0, 255), 2, 8, 0);
    }
    return color_image;
}
int main()
{

    const auto window_name = "Display color_Image";
    namedWindow(window_name, WINDOW_AUTOSIZE);
    Mat color_image;
    color_image = imread("Rui.jpg");
    color_image = Facejudge(color_image);
    imshow(window_name, color_image);

    return 0;
}

运行结果

 不是很明白为什么。

       如果有哪位大佬知道可以告诉我...

猜你喜欢

转载自blog.csdn.net/m0_61897853/article/details/123934718