精华内容
下载资源
问答
  • OpenCV级联分类器Cascade Classifier级联分类器Cascade Classifier目标理论OpenCV中的Haar级联检测结果 级联分类器Cascade Classifier 目标 在本教程中, 我们将学习Haar级联对象检测的工作原理。 我们将使用基于...

    级联分类器Cascade Classifier

    目标

    在本教程中,
    我们将学习Haar级联对象检测的工作原理。
    我们将使用基于Haar Feature的Cascade分类器了解人脸检测和眼睛检测的基础知识
    我们将使用cv :: CascadeClassifier类来检测视频流中的对象。特别是,我们将使用以下功能:
    cv :: CascadeClassifier :: load来加载.xml分类器文件。它可以是Haar或LBP分类器
    cv :: CascadeClassifier :: detectMultiScale执行检测。

    理论

    使用基于Haar特征的级联分类器进行对象检测是Paul Viola和Michael Jones在其论文“使用简单特征的增强级联进行快速对象检测”中于2001年提出的一种有效的对象检测方法。这是一种基于机器学习的方法,其中从许多正负图像中训练级联函数。然后用于检测其他图像中的对象。
    在这里,我们将进行人脸检测。最初,该算法需要大量正图像(面部图像)和负图像(无面部图像)来训练分类器。然后,我们需要从中提取特征。为此,使用下图所示的Haar功能。它们就像我们的卷积核一样。每个特征都是通过从黑色矩形下的像素总和中减去白色矩形下的像素总和而获得的单个值。
    在这里插入图片描述
    现在,每个内核的所有可能大小和位置都用于计算许多功能。(试想一下它需要多少计算?即使是24x24的窗口也会产生超过160000个特征)。对于每个特征计算,我们需要找到白色和黑色矩形下的像素总和。为了解决这个问题,他们引入了整体形象。无论您的图像有多大,它都会将给定像素的计算减少到仅涉及四个像素的操作。很好,不是吗?它使事情变得超快。

    但是在我们计算的所有这些功能中,大多数都不相关。例如,考虑下图。第一行显示了两个良好的功能。选择的第一个特征似乎着眼于眼睛的区域通常比鼻子和脸颊的区域更暗的属性。选择的第二个功能取决于眼睛比鼻子的鼻梁更黑的属性。但是,将相同的窗口应用于脸颊或其他任何地方都是无关紧要的。那么,我们如何从160000多个功能中选择最佳功能?它是由Adaboost实现的。
    在这里插入图片描述
    为此,我们将所有功能应用于所有训练图像。对于每个特征,它会找到最佳的阈值,该阈值会将人脸分为正值和负值。显然,会有错误或分类错误。我们选择错误率最低的特征,这意味着它们是对人脸和非人脸图像进行最准确分类的特征。(此过程并非如此简单。在开始时,每个图像的权重均相等。在每次分类后,错误分类的图像的权重都会增加。然后执行相同的过程。将计算新的错误率。还要计算新的权重。继续进行此过程,直到达到所需的精度或错误率或找到所需的功能数量为止。

    最终分类器是这些弱分类器的加权和。之所以称其为弱,是因为它本身无法对图像进行分类,而是与其他图像一起构成了强大的分类器。该论文说,甚至200个功能都可以提供95%的准确度检测。他们的最终设置具有大约6000个功能。(想象一下,从160000多个功能减少到6000个功能。这是一个很大的收获)。

    因此,现在您拍摄一张照片。取每个24x24窗口。向其应用6000个功能。检查是否有脸。哇…这不是效率低下又费时吗?是的。作者对此有一个很好的解决方案。

    在图像中,大多数图像是非脸部区域。因此,最好有一种简单的方法来检查窗口是否不是面部区域。如果不是,请一次性丢弃它,不要再次对其进行处理。相反,重点放在可能有脸的区域。这样,我们将花费更多时间检查可能的面部区域。

    为此,他们引入了级联分类器的概念。不是将所有6000个功能部件应用到一个窗口中,而是将这些功能部件分组到不同的分类器阶段,并一一应用。(通常,前几个阶段将包含很少的功能)。如果窗口在第一阶段失败,则将其丢弃。我们不考虑其上的其余功能。如果通过,则应用功能的第二阶段并继续该过程。经过所有阶段的窗口是一个面部区域。这个计划怎么样!

    作者的检测器具有6000多个特征,具有38个阶段,在前五个阶段具有1、10、25、25和50个特征。(上图中的两个功能实际上是从Adaboost获得的最佳两个功能)。根据作者的说法,每个子窗口平均评估了6000多个特征中的10个特征。

    因此,这是Viola-Jones人脸检测工作原理的简单直观说明。

    OpenCV中的Haar级联检测

    OpenCV提供了一种训练方法或预训练模型,可以使用cv :: CascadeClassifier :: load方法读取该模型。预训练的模型位于OpenCV安装的data文件夹中,或在此处找到。

    以下代码示例将使用预训练的Haar级联模型来检测图像中的脸部和眼睛。首先,创建一个cv :: CascadeClassifier并使用cv :: CascadeClassifier :: load方法加载必要的XML文件。然后,使用cv :: CascadeClassifier :: detectMultiScale方法完成检测,该方法返回检测到的脸部或眼睛的边界矩形。

    #include "opencv2/objdetect.hpp"
    #include "opencv2/highgui.hpp"
    #include "opencv2/imgproc.hpp"
    #include "opencv2/videoio.hpp"
    #include <iostream>
    using namespace std;
    using namespace cv;
    void detectAndDisplay( Mat frame );
    CascadeClassifier face_cascade;
    CascadeClassifier eyes_cascade;
    int main( int argc, const char** argv )
    {
        CommandLineParser parser(argc, argv,
                                 "{help h||}"
                                 "{face_cascade|data/haarcascades/haarcascade_frontalface_alt.xml|Path to face cascade.}"
                                 "{eyes_cascade|data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|Path to eyes cascade.}"
                                 "{camera|0|Camera device number.}");
        parser.about( "\nThis program demonstrates using the cv::CascadeClassifier class to detect objects (Face + eyes) in a video stream.\n"
                      "You can use Haar or LBP features.\n\n" );
        parser.printMessage();
        String face_cascade_name = samples::findFile( parser.get<String>("face_cascade") );
        String eyes_cascade_name = samples::findFile( parser.get<String>("eyes_cascade") );
        //-- 1. Load the cascades
        if( !face_cascade.load( face_cascade_name ) )
        {
            cout << "--(!)Error loading face cascade\n";
            return -1;
        };
        if( !eyes_cascade.load( eyes_cascade_name ) )
        {
            cout << "--(!)Error loading eyes cascade\n";
            return -1;
        };
        int camera_device = parser.get<int>("camera");
        VideoCapture capture;
        //-- 2. Read the video stream
        capture.open( camera_device );
        if ( ! capture.isOpened() )
        {
            cout << "--(!)Error opening video capture\n";
            return -1;
        }
        Mat frame;
        while ( capture.read(frame) )
        {
            if( frame.empty() )
            {
                cout << "--(!) No captured frame -- Break!\n";
                break;
            }
            //-- 3. Apply the classifier to the frame
            detectAndDisplay( frame );
            if( waitKey(10) == 27 )
            {
                break; // escape
            }
        }
        return 0;
    }
    void detectAndDisplay( Mat frame )
    {
        Mat frame_gray;
        cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
        equalizeHist( frame_gray, frame_gray );
        //-- Detect faces
        std::vector<Rect> faces;
        face_cascade.detectMultiScale( frame_gray, faces );
        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 ), 4 );
            Mat faceROI = frame_gray( faces[i] );
            //-- In each face, detect eyes
            std::vector<Rect> eyes;
            eyes_cascade.detectMultiScale( faceROI, eyes );
            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 ), 4 );
            }
        }
        //-- Show what you got
        imshow( "Capture - Face detection", frame );
    }
    

    结果

    这是运行上面的代码并将内置摄像头的视频流用作输入的结果:
    在这里插入图片描述
    确保程序会找到文件haarcascade_frontalface_alt.xml和haarcascade_eye_tree_eyeglasses.xml的路径。它们位于opencv / data / haarcascades中

    这是因为使用文件lbpcascade_frontalface.xml(受LBP训练)来进行人脸检测。对于眼睛,我们继续使用本教程中使用的文件。
    在这里插入图片描述

    展开全文
  • OpenCV级联分类器训练与使用教程与代码11111111111111111111111
  • openCV 级联分类器

    千次阅读 2015-07-04 19:16:53
     本文转自:   http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guide/ug_traincascade.html... 级联分类器训练 介绍 级联分类器包括两部分:训练和检测。 检测部分在OpenCV obj
    

    本文转自:  

     http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guide/ug_traincascade.html                                                    

     级联分类器训练

    介绍

    级联分类器包括两部分:训练和检测。 检测部分在OpenCV objdetect 模块的文档中有介绍,在那文档中给出了一些级联分类器的基本介绍。这个指南是描述如何训练分类器:准备训练数据和运行训练程序。

    重点注意事项

    OpenCV中有两个程序可以训练级联分类器: opencv_haartraining and opencv_traincascade``。 ``opencv_traincascade 是一个新程序,使用OpenCV 2.x API 以C++ 编写。这二者主要的区别是 opencv_traincascade 支持 Haar [Viola2001] 和 LBP [Liao2007] (Local Binary Patterns) 两种特征,并易于增加其他的特征。与Haar特征相比,LBP特征是整数特征,因此训练和检测过程都会比Haar特征快几倍。LBP和Haar特征用于检测的准确率,是依赖训练过程中的训练数据的质量和训练参数。训练一个与基于Haar特征同样准确度的LBP的分类器是可能的。

    opencv_traincascade and opencv_haartraining 所输出的分类器文件格式并不相同。注意,新的级联检测接口(参考 objdetect 模块中的 CascadeClassifier 类)支持这两种格式。 opencv_traincascade 可以旧格式导出选练好的级联分类器。但是在训练过程被中断后再重启训练过程, opencv_traincascade and opencv_haartraining 不能装载与中断前不同的文件格式。

    opencv_traincascade 程序使用TBB来处理多线程。如果希望使用多核并行运算加速,请使用TBB来编译OpenCV。

    还有一些与训练相关的辅助程序。

    • opencv_createsamples 用来准备训练用的正样本数据和测试数据。 opencv_createsamples 能够生成能被 opencv_haartraining opencv_traincascade 程序支持的正样本数据。它的输出为以 *.vec 为扩展名的文件,该文件以二进制方式存储图像。
    • opencv_performance 可以用来评估分类器的质量,但只能评估 opencv_haartraining 输出的分类器。它读入一组标注好的图像,运行分类器并报告性能,如检测到物体的数目,漏检的数目,误检的数目,以及其他信息。

    既然 opencv_haartraining 是一个将被弃用的程序,下面将不再介绍,而会主要介绍 opencv_traincascade opencv_createsamples 程序用来为 opencv_traincascade 准备训练样本,因此也会介绍它。

    准备训练数据

    训练需要一些列样本。样本分两类:负样本和正样本。负样本是指不包括物体的图像。正样本是待检测的物体的图像。负样本必须手工准备,正样本使用 opencv_createsamples 创建。

    负样本

    负样本可以是任意图像,但是这些图像中不能包含待检测的物体。用于抠取负样本的图像文件名被列在一个文件中。这个文件是纯文本文件,每行是一个文件名(包括相对目录和文件名)。负样本和样本图像也叫做背景样本,或者背景样本图像,本文档中对之不予区分。这些图像可以是不同的尺寸,但是图像尺寸应该比训练窗口的尺寸大,因为这些图像将被用于抠取负样本,并将负样本缩小到训练窗口大小。

    下面是一个描述文件的例子:

    假如目录结构如下:

    /img
      img1.jpg
      img2.jpg
    bg.txt
    

    则bg.txt文件中的内容将如下所示:

    img/img1.jpg
    img/img2.jpg
    

    正样本

    正样本由 opencv_createsamples 生成。正样本可以由包含待检测物体的一张图片生成,也可由一系列标记好的图像生成。

    请注意你需要一个很大的负样本库送给训练程序进行训练。如果是绝对刚性的物体,如OpenCV的标志,你只有一张正样本图像;如果是人脸,你需要几百甚至几千个正样本。在待检测物体是人脸的情况下,你需要考虑所有的人种、年龄、表情甚至胡子的样式。

    如果只有一张包含物体的图像,如一个公司的标志,那么可以通过对物体图像的随机旋转、改变标志亮度以及将标志放在任意的背景上而获得大量的正样本。生成的正样本数目以及随机的程度都可以通过 opencv_createsamples 的命令行参数控制。

    命令行参数:

    • -vec <vec_file_name>

      输出文件,内含用于训练的正样本。

    • -img <image_file_name>

      输入图像文件名(例如一个公司的标志)。

    • -bg <background_file_name>

      背景图像的描述文件,文件中包含一系列的图像文件名,这些图像将被随机选作物体的背景。

    • -num <number_of_samples>

      生成的正样本的数目。

    • -bgcolor <background_color>

      背景颜色(目前为灰度图);背景颜色表示透明颜色。因为图像压缩可造成颜色偏差,颜色的容差可以由 -bgthresh 指定。所有处于 bgcolor-bgthreshbgcolor+bgthresh 之间的像素都被设置为透明像素。

    • -bgthresh <background_color_threshold>

    • -inv

      如果指定该标志,前景图像的颜色将翻转。

    • -randinv

      如果指定该标志,颜色将随机地翻转。

    • -maxidev <max_intensity_deviation>

      前景样本里像素的亮度梯度的最大值。

    • -maxxangle <max_x_rotation_angle>

      X轴最大旋转角度,必须以弧度为单位。

    • -maxyangle <max_y_rotation_angle>

      Y轴最大旋转角度,必须以弧度为单位。

    • -maxzangle <max_z_rotation_angle>

      Z轴最大旋转角度,必须以弧度为单位。

    • -show

      很有用的调试选项。如果指定该选项,每个样本都将被显示。如果按下 Esc 键,程序将继续创建样本但不再显示。

    • -w <sample_width>

      输出样本的宽度(以像素为单位)。

    • -h <sample_height>

      输出样本的高度(以像素为单位)。

    创建样本的流程如下: 输入图像沿着三个轴随机旋转。旋转的角度由 -max?angle 限定。然后像素的亮度值位于 [bg_color-bg_color_threshold; bg_color+bg_color_threshold]范围的像素被设置为透明像素。将白噪声加到前景图像上。如果指定了 -inv ,那么前景图像的颜色将被翻转。如果指定了 -randinv ,程序将随机选择是否将颜色进行翻转。任选背景图像,将获得的前景图像放到背景图像上,并将图像调整到 -w -h 指定的大小。最后将图像存入vec文件,vec文件名由命令行参数 -vec 指定。

    正样本也可从一系列事先标记好的图像中创建。标记信息可以存储于一个文本文件,与背景描述文件类似。文件中的每行对应一个图像文件。每行的第一个元素为图像文件名,后面是物体的数目,最后是物体位置和大小的描述 (x, y, width, height)。

    下面是描述文件的例子:

    假设目录结构如下:

    /img
      img_with_faces_1.jpg
      img_with_faces_2.jpg
    info.dat
    

    文件info.dat里的内容如下:

    img/img_with_faces_1.jpg  1  140 100 45 45
    img/img_with_faces_2.jpg  2  100 200 50 50   50 30 25 25
    

    图像img_with_faces_1.jpg中包含一个物体实例(如人脸),标示其在图像中的位置和大小的矩形为(140, 100, 45, 45)。图像img_with_faces_2.jpg包含两个物体实例。

    从这样的一系列数据中创建正样本,需要在命令行指定 -info 而非前面所用的 -img 参数:

    • -info <collection_file_name>

      描述物体所在图像以及大小位置的描述文件。

    此部分样本创建过程如下:将物体实例从图像中抠取出,然后将之调整尺寸到目标尺寸,然后保存到输出的vec文件。在此过程中不会对图像进行变形,所以有效的命令行参数仅有 -w, -h, -show-num

    opencv_createsamples 也可以用来查看和检查保存于vec正样本文件中的正样本。这时只需指定 -vec -w-h 三个参数则可。 opencv_createsamples 将逐一显示正样本图像。

    在训练中,训练程序并不关心包含正样本的vec文件如何生成的,你可以自己写程序来生成vec文件。但是OpenCV提供的工具中,只有 opencv_createsamples 程序能够创建包含正样本的vec文件。

    一个vec文件的例子位于 opencv/data/vec_files/trainingfaces_24-24.vec 。它可用来训练人脸分类器,窗口大小为: -w 24 -h 24

    训练级联分类器

    下一步是训练分类器。如前面所述, opencv_traincascadeopencv_haartraining 都可用来训练一个级联分类器,但是此处只介绍 opencv_traincascade opencv_haartraining 的用法与 opencv_traincascade 类似。

    下面是 opencv_traincascade 的命令行参数,以用途分组介绍:

    1. 通用参数:

      • -data <cascade_dir_name>

        目录名,如不存在训练程序会创建它,用于存放训练好的分类器。

      • -vec <vec_file_name>

        包含正样本的vec文件名(由 opencv_createsamples 程序生成)。

      • -bg <background_file_name>

        背景描述文件,也就是包含负样本文件名的那个描述文件。

      • -numPos <number_of_positive_samples>

        每级分类器训练时所用的正样本数目。

      • -numNeg <number_of_negative_samples>

        每级分类器训练时所用的负样本数目,可以大于 -bg 指定的图片数目。

      • -numStages <number_of_stages>

        训练的分类器的级数。

      • -precalcValBufSize <precalculated_vals_buffer_size_in_Mb>

        缓存大小,用于存储预先计算的特征值(feature values),单位为MB。

      • -precalcIdxBufSize <precalculated_idxs_buffer_size_in_Mb>

        缓存大小,用于存储预先计算的特征索引(feature indices),单位为MB。内存越大,训练时间越短。

      • -baseFormatSave

        这个参数仅在使用Haar特征时有效。如果指定这个参数,那么级联分类器将以老的格式存储。

    2. 级联参数:

      • -stageType <BOOST(default)>

        级别(stage)参数。目前只支持将BOOST分类器作为级别的类型。

      • -featureType<{HAAR(default), LBP}>

        特征的类型: HAAR - 类Haar特征; LBP - 局部纹理模式特征。

      • -w <sampleWidth>

      • -h <sampleHeight>

        训练样本的尺寸(单位为像素)。必须跟训练样本创建(使用 opencv_createsamples 程序创建)时的尺寸保持一致。

    3. Boosted分类器参数:

      • -bt <{DAB, RAB, LB, GAB(default)}>

        Boosted分类器的类型: DAB - Discrete AdaBoost, RAB - Real AdaBoost, LB - LogitBoost, GAB - Gentle AdaBoost。

      • -minHitRate <min_hit_rate>

        分类器的每一级希望得到的最小检测率。总的检测率大约为 min_hit_rate^number_of_stages。

      • -maxFalseAlarmRate <max_false_alarm_rate>

        分类器的每一级希望得到的最大误检率。总的误检率大约为 max_false_alarm_rate^number_of_stages.

      • -weightTrimRate <weight_trim_rate>

        Specifies whether trimming should be used and its weight. 一个还不错的数值是0.95。

      • -maxDepth <max_depth_of_weak_tree>

        弱分类器树最大的深度。一个还不错的数值是1,是二叉树(stumps)。

      • -maxWeakCount <max_weak_tree_count>

        每一级中的弱分类器的最大数目。The boosted classifier (stage) will have so many weak trees (<=maxWeakCount), as needed to achieve the given -maxFalseAlarmRate.

    4. 类Haar特征参数:

      • -mode <BASIC (default) | CORE | ALL>

        选择训练过程中使用的Haar特征的类型。 BASIC 只使用右上特征, ALL 使用所有右上特征和45度旋转特征。更多细节请参考 [Rainer2002]

    5. LBP特征参数:

      LBP特征无参数。

    opencv_traincascade 程序训练结束以后,训练好的级联分类器将存储于文件cascade.xml中,这个文件位于 -data 指定的目录中。这个目录中的其他文件是训练的中间结果,当训练程序被中断后,再重新运行训练程序将读入之前的训练结果,而不需从头重新训练。训练结束后,你可以删除这些中间文件。

    训练结束后,你就可以测试你训练好的级联分类器了!

    [Viola2001] Paul Viola, Michael Jones. Rapid Object Detection using a Boosted Cascade of Simple Features. Conference on Computer Vision and Pattern Recognition (CVPR), 2001, pp. 511-518. [Rainer2002] Rainer Lienhart and Jochen Maydt. An Extended Set of Haar-like Features for Rapid Object Detection. Submitted to ICIP2002. [Liao2007] Shengcai Liao, Xiangxin Zhu, Zhen Lei, Lun Zhang and Stan Z. Li. Learning Multi-scale Block Local Binary Patterns for Face Recognition. International Conference on Biometrics (ICB), 2007, pp. 828-837.
    展开全文
  • opencv 级联分类器

    千次阅读 2018-05-24 15:32:32
    转自:https://blog.csdn.net/wuxiaoyao12/article/details/39227189好久没有来写blog了,学生生涯终结,就不好好总结了,今天...见绿色)一、基础知识准备首先,opencv目前仅支持三种特征的训练检测, HAAR、LBP、H...

    转自:https://blog.csdn.net/wuxiaoyao12/article/details/39227189

    好久没有来写blog了,学生生涯终结,就不好好总结了,今天把opencv里关于adaboost训练和检测的过程记录下来,方便别人也方便自己~~~啊哈哈~~~~大笑

    (2015.8.28更改,见绿色)

    一、基础知识准备

    首先,opencv目前仅支持三种特征的训练检测, HAAR、LBP、HOG,选择哪个特征就去补充哪个吧。opencv的这个训练算法是基于adaboost而来的,所以需要先对adaboost进行基础知识补充啊,网上一大堆资料,同志们速度去查阅。我的资源里也有,大家去下载吧,这些我想都不是大家能直接拿来用的,我下面将直接手把手告诉大家训练怎么操作,以及要注意哪些细节。


    二、关于正样本的准备

    1、采集正样本图片

    因为正样本最后需要大小归一化,所以我在采集样本的时候就直接把它从原图里抠出来了,方便后面缩放嘛,而不是只保存它的框个数和框位置信息(框个数、框位置信息看下一步解释),在裁剪的过程中尽量保持样本的长宽比例一致。比如我最后要归一化成20 X 20,在裁剪样本的时候,我都是20X20或者21X21、22X22等等,最大我也没有超过30X30(不超过跟我的自身用途有关,对于人脸检测这种要保证缩放不变性的样本,肯定就可以超过啦),我资源里也给出可以直接用的裁剪样本程序。

    (这里我说错了,根据createsamples.cpp ,我们不需要提前进行缩放操作,它在第3步变成vec时就包含了缩放工作.如果我们是用objectMaker标记样本,程序同时生成的关于每一幅图的samplesInfo信息,直接给第三步用即可。当然,你提前缩放了也没关系,按照第2步操作即可)

    2、获取正样本路径列表

    在你的图片文件夹里,编写一个bat程序(get route.bat,bat是避免每次都需要去dos框输入,那里又不能复制又不能粘贴!),如下所示:








    运行bat文件,就会生成如下dat文件:


    把这个dat文件中的所有非图片的路径都删掉,比如上图的头两行,再将bmp 替换成 bmp 1 0 0 20 20,如下:


    (1代表个数,后四个分别对应 left top width height,如果我们之前不是把样本裁剪下来的,那么你的这个dat可能就长成这样1. bmp 3 1 3 24 24 26 28 25 25 60 80 26 26,1.bmp是完全的原图啊,你之前的样本就是从这张图上扣下来的)

    3、获取供训练的vec文件

    这里,我们得利用opencv里的一个程序叫opencv_createsamples.exe,可以把它拷贝出来。针对它的命令输入也是写成bat文件啦,因为cascade训练的时候用的是vec。如下:


    运行bat,就在我们得pos文件夹里生成了如下vec文件:

    就此有关正样本的东西准备结束。

    (vec中其实就是保存的每一个sample图,并且已经统一w、h大小了,如果你想看所有的sample,也可以通过调用opencv_createsamples.exe,使用操作,见附)


    三、关于负样本的准备

    这个特别简单,直接拿原始图,不需要裁剪抠图(不裁剪还能保证样本的多样性),也不需要保存框(网上说只要保证比正样本大小大哈,大家就保证吧),只要把路径保存下来。同正样本类似,步骤图如下:



    至此有关负样本的也准备完成。


    四、开始训练吧

    这里我们用opencv_traincascade.exe(opencv_haartraining.exe的用法跟这个很相似,具体需要输入哪些参数去看opencv的源码吧,网上资料也有很多,主要是opencv_traincascade.exe比opencv_haartraining.exe包含更多的特征,功能齐全些啊),直接上图:


    命令输入也直接用bat文件,请务必保证好大小写一致,不然不予识别参数。小白兔,跑起来~~~


    这是程序识别到的参数,没有错把,如果你哪个字母打错了,你就会发现这些参数会跟你预设的不一样啊,所以大家一定要看清楚了~~~~

    跑啊跑啊跑啊跑,如下:


    这一级的强训练器达到你预设的比例以后就跑去训练下一级了,同志们那个HR比例不要设置太高,不然会需要好多样本,然后stagenum不要设置太小啊,不然到时候拿去检测速度会很慢。

    等这个bat跑结束,我的xml文件也生成了。如下:


    其实这个训练可以中途停止的,因为下次开启时它会读取这些xml文件,接着进行上次未完成的训练。哈哈~~~~好人性化啊!

    训练结束,我要到了我的cascade.xml文件,现在我要拿它去做检测了啊!呼呼~~~~


    五、开始检测吧

    opencv有个opencv_performance.exe程序用于检测,但是它只能用在用opencv_haartraining.exe来用的,所以我这里是针对一些列图片进行检测的,检测代码如下:

    1. #include <windows.h>  
    2. #include <mmsystem.h>  
    3. #include <stdio.h>  
    4. #include <stdlib.h>  
    5. #include "wininet.h"  
    6. #include <direct.h>  
    7. #include <string.h>  
    8. #include <list>  
    9. #pragma comment(lib,"Wininet.lib")  
    10.   
    11.   
    12. #include "opencv2/objdetect/objdetect.hpp"  
    13. #include "opencv2/highgui/highgui.hpp"  
    14. #include "opencv2/imgproc/imgproc.hpp"  
    15. #include "opencv2/ml/ml.hpp"  
    16.   
    17. #include <iostream>  
    18. #include <stdio.h>  
    19.   
    20. using namespace std;  
    21. using namespace cv;  
    22.   
    23. String cascadeName = "./cascade.xml";//训练数据  
    24.   
    25. struct PathElem{  
    26.     TCHAR   SrcImgPath[MAX_PATH*2];  
    27.     TCHAR   RstImgPath[MAX_PATH*2];  
    28. };  
    29. int FindImgs(char * pSrcImgPath, char * pRstImgPath, std::list<PathElem> &ImgList);  
    30.   
    31. int main( )  
    32. {  
    33.     CascadeClassifier cascade;//创建级联分类器对象  
    34.     std::list<PathElem> ImgList;   
    35.     std::list<PathElem>::iterator pImgListTemp;   
    36.     vector<Rect> rects;  
    37.     vector<Rect>::const_iterator pRect;  
    38.   
    39.     double scale = 1.;  
    40.     Mat image;  
    41.     double t;  
    42.     if( !cascade.load( cascadeName ) )//从指定的文件目录中加载级联分类器  
    43.     {  
    44.         cerr << "ERROR: Could not load classifier cascade" << endl;  
    45.         return 0;  
    46.     }  
    47.   
    48.       
    49.     int nFlag = FindImgs("H:/SrcPic/","H:/RstPic/", ImgList);         
    50.     if(nFlag != 0)     
    51.     {  
    52.         cout<<"Read Image  error !  Input 0 to exit \n";  
    53.         exit(0);  
    54.     }  
    55.   
    56.     pImgListTemp = ImgList.begin();  
    57.     for(int iik = 1; iik <= ImgList.size(); iik++,pImgListTemp++)  
    58.     {  
    59.         image = imread(pImgListTemp->SrcImgPath);      
    60.         if( !image.empty() )//读取图片数据不能为空  
    61.         {  
    62.             Mat gray, smallImg( cvRound (image.rows/scale), cvRound(image.cols/scale), CV_8UC1 );//将图片缩小,加快检测速度  
    63.             cvtColor( image, gray, CV_BGR2GRAY );//因为用的是类haar特征,所以都是基于灰度图像的,这里要转换成灰度图像  
    64.             resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );//将尺寸缩小到1/scale,用线性插值  
    65.             equalizeHist( smallImg, smallImg );//直方图均衡  
    66.   
    67.             //detectMultiScale函数中smallImg表示的是要检测的输入图像为smallImg,rects表示检测到的目标序列,1.1表示  
    68.             //每次图像尺寸减小的比例为1.1,2表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗口大  
    69.             //小都可以检测到目标),CV_HAAR_SCALE_IMAGE表示不是缩放分类器来检测,而是缩放图像,Size(30, 30)为目标的  
    70.             //最小最大尺寸  
    71.             rects.clear();  
    72.             printf( "begin...\n");  
    73.             t = (double)cvGetTickCount();//用来计算算法执行时间  
    74.             cascade.detectMultiScale(smallImg,rects,1.1,2,0,Size(20,20),Size(30,30));  
    75.             //|CV_HAAR_FIND_BIGGEST_OBJECT//|CV_HAAR_DO_ROUGH_SEARCH|CV_HAAR_SCALE_IMAGE,  
    76.   
    77.             t = (double)cvGetTickCount() - t;  
    78.             printf( "detection time = %g ms\n\n", t/((double)cvGetTickFrequency()*1000.) );  
    79.             for(pRect = rects.begin(); pRect != rects.end(); pRect++)  
    80.             {  
    81.                 rectangle(image,cvPoint(pRect->x,pRect->y),cvPoint(pRect->x+pRect->width,pRect->y+pRect->height),cvScalar(0,255,0));  
    82.             }  
    83.             imwrite(pImgListTemp->RstImgPath,image);  
    84.         }  
    85.     }  
    86.       
    87.     return 0;  
    88. }  
    89.   
    90. int FindImgs(char * pSrcImgPath, char * pRstImgPath, std::list<PathElem> &ImgList)  
    91. {  
    92.     //源图片存在的目录  
    93.     TCHAR   szFileT1[MAX_PATH*2];  
    94.     lstrcpy(szFileT1,TEXT(pSrcImgPath));     
    95.     lstrcat(szFileT1, TEXT("*.*"));  
    96.   
    97.     //结果图片存放的目录  
    98.     TCHAR   RstAddr[MAX_PATH*2];   
    99.     lstrcpy(RstAddr,TEXT(pRstImgPath));  
    100.     _mkdir(RstAddr);   //创建文件夹  
    101.   
    102.     WIN32_FIND_DATA   wfd;    
    103.     HANDLE   hFind   =   FindFirstFile(szFileT1, &wfd);   
    104.   
    105.   
    106.     PathElem stPathElemTemp;  
    107.     if(hFind != INVALID_HANDLE_VALUE)     
    108.     {  
    109.         do   
    110.         {   
    111.             if(wfd.cFileName[0] == TEXT('.'))   
    112.                 continue;  
    113.             if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY || strcmp("Thumbs.db", TEXT(wfd.cFileName)) == 0)   
    114.             {   
    115.                 ;  
    116.             }    
    117.             else   
    118.             {   
    119.   
    120.                 TCHAR   SrcImgPath[MAX_PATH*2];  
    121.                 lstrcpy(SrcImgPath, pSrcImgPath);   
    122.                 lstrcat(SrcImgPath, TEXT(wfd.cFileName));  
    123.   
    124.                 lstrcpy(stPathElemTemp.SrcImgPath, SrcImgPath);   
    125.   
    126.                 TCHAR   AdressTemp[MAX_PATH*2];  
    127.                 lstrcpy(AdressTemp,pRstImgPath);   
    128.   
    129.                 //lstrcat(AdressTemp, TEXT("/"));    
    130.                 lstrcat(AdressTemp, TEXT(wfd.cFileName));    
    131.                 lstrcpy(stPathElemTemp.RstImgPath, AdressTemp);   
    132.   
    133.                 ImgList.push_back(stPathElemTemp);  
    134.   
    135.             }  
    136.         }while(FindNextFile(hFind, &wfd));  
    137.     }  
    138.     else  
    139.     {  
    140.         return -1;  
    141.     }  
    142.     return 0;  
    143. }  

    自己看看自己的检测结果咯。效果不好的改进样本,调整训练参数吧~~~嘎嘎


    我觉得我写的够白痴,很方便大家直接拿来用。其中一些细节,大家自己琢磨吧~88



    附:

    1、opencv_createsamples.exe的参数

    (createsamples.cpp)

    1. "  [-info <collection_file_name>]\n"  
    2. "  [-img <image_file_name>]\n"  
    3. "  [-vec <vec_file_name>]\n"  
    4. "  [-bg <background_file_name>]\n  [-num <number_of_samples = %d>]\n"  
    5. "  [-bgcolor <background_color = %d>]\n"  
    6. "  [-inv] [-randinv] [-bgthresh <background_color_threshold = %d>]\n"  
    7. "  [-maxidev <max_intensity_deviation = %d>]\n"  
    8. "  [-maxxangle <max_x_rotation_angle = %f>]\n"  
    9. "  [-maxyangle <max_y_rotation_angle = %f>]\n"  
    10. "  [-maxzangle <max_z_rotation_angle = %f>]\n"  
    11. "  [-show [<scale = %f>]]\n"  
    12. "  [-w <sample_width = %d>]\n  [-h <sample_height = %d>]\n"//默认24*24  

    以下1)~4)是按顺序判断,且有且仅有一个

    1)提供imagename 和vecname时,调用以下操作
    1. /* 
    2.  * cvCreateTrainingSamples 
    3.  * 
    4.  * Create training samples applying random distortions to sample image and 
    5.  * store them in .vec file 
    6.  * 
    7.  * filename        - .vec file name 
    8.  * imgfilename     - sample image file name 
    9.  * bgcolor         - background color for sample image 
    10.  * bgthreshold     - background color threshold. Pixels those colors are in range 
    11.  *   [bgcolor-bgthreshold, bgcolor+bgthreshold] are considered as transparent 
    12.  * bgfilename      - background description file name. If not NULL samples 
    13.  *   will be put on arbitrary background 
    14.  * count           - desired number of samples 
    15.  * invert          - if not 0 sample foreground pixels will be inverted 
    16.  *   if invert == CV_RANDOM_INVERT then samples will be inverted randomly 
    17.  * maxintensitydev - desired max intensity deviation of foreground samples pixels 
    18.  * maxxangle       - max rotation angles 
    19.  * maxyangle 
    20.  * maxzangle 
    21.  * showsamples     - if not 0 samples will be shown 
    22.  * winwidth        - desired samples width 
    23.  * winheight       - desired samples height 
    24.  */  
    2)提供imagename、bgfilename和infoname时
    与1)类似
    3)提供 infoname和 vecname时,调用以下操作(这里是我们训练需要的)
    1. /* 
    2.  * cvCreateTrainingSamplesFromInfo 
    3.  * 
    4.  * Create training samples from a set of marked up images and store them into .vec file 
    5.  * infoname    - file in which marked up image descriptions are stored 
    6.  * num         - desired number of samples 
    7.  * showsamples - if not 0 samples will be shown 
    8.  * winwidth    - sample width 
    9.  * winheight   - sample height 
    10.  *  
    11.  * Return number of successfully created samples 
    12.  */  
    13. int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilename,  
    14.                                      int num,  
    15.                                      int showsamples,  
    16.                                      int winwidth, int winheight )  

    函数内容:读取当前图中所有标记的sample(x,y,w,h),并将其缩放到winwidth、winheight大小,故在这之前的人为缩放操作不需要

    (可以看到,仅需要num、w、h参数)
    4)仅vecname时,可以将vec里面的所有缩放后的samples都显示出来
    1. /* 
    2.  * cvShowVecSamples 
    3.  * 
    4.  * Shows samples stored in .vec file 
    5.  * 
    6.  * filename 
    7.  *   .vec file name 
    8.  * winwidth 
    9.  *   sample width 
    10.  * winheight 
    11.  *   sample height 
    12.  * scale 
    13.  *   the scale each sample is adjusted to(这个scale与3中的缩放不是一回事,这里仅为了显示而再次缩放) 
    14.  */  
    15. void cvShowVecSamples( const char* filename, int winwidth, int winheight, double scale );  

    2、opencv_haartraining.exe的参数

    (haartraining.cpp )

    1. "  -data <dir_name>\n"  
    2. "  -vec <vec_file_name>\n"  
    3. "  -bg <background_file_name>\n"  
    4. "  [-bg-vecfile]\n"  
    5. "  [-npos <number_of_positive_samples = %d>]\n"  
    6. "  [-nneg <number_of_negative_samples = %d>]\n"  
    7. "  [-nstages <number_of_stages = %d>]\n"  
    8. "  [-nsplits <number_of_splits = %d>]\n"  
    9. "  [-mem <memory_in_MB = %d>]\n"  
    10. "  [-sym (default)] [-nonsym]\n"  
    11. "  [-minhitrate <min_hit_rate = %f>]\n"  
    12. "  [-maxfalsealarm <max_false_alarm_rate = %f>]\n"  
    13. "  [-weighttrimming <weight_trimming = %f>]\n"  
    14. "  [-eqw]\n"  
    15. "  [-mode <BASIC (default) | CORE | ALL>]\n"  
    16. "  [-w <sample_width = %d>]\n"  
    17. "  [-h <sample_height = %d>]\n"  
    18. "  [-bt <DAB | RAB | LB | GAB (default)>]\n"  
    19. "  [-err <misclass (default) | gini | entropy>]\n"  
    20. "  [-maxtreesplits <max_number_of_splits_in_tree_cascade = %d>]\n"  
    21. "  [-minpos <min_number_of_positive_samples_per_cluster = %d>]\n"  

    3、opencv_performance.exe参数

    (performance.cpp )

    1. "  -data <classifier_directory_name>\n"  
    2. "  -info <collection_file_name>\n"  
    3. "  [-maxSizeDiff <max_size_difference = %f>]\n"  
    4. "  [-maxPosDiff <max_position_difference = %f>]\n"  
    5. "  [-sf <scale_factor = %f>]\n"  
    6. "  [-ni <saveDetected = 0>]\n"  
    7. "  [-nos <number_of_stages = %d>]\n"  
    8. "  [-rs <roc_size = %d>]\n"  
    9. "  [-w <sample_width = %d>]\n"  
    10. "  [-h <sample_height = %d>]\n"  


    4、opencv_traincascade.exe参数说明

    ——traincascade.cpp 

    1.  cout << "Usage: " << argv[0] << endl;  
    2.  cout << "  -data <cascade_dir_name>" << endl;  
    3.  cout << "  -vec <vec_file_name>" << endl;  
    4.  cout << "  -bg <background_file_name>" << endl;  
    5.  cout << "  [-numPos <number_of_positive_samples = " << numPos << ">]" << endl;   //默认2000  
    6.  cout << "  [-numNeg <number_of_negative_samples = " << numNeg << ">]" << endl;   //默认1000  
    7.  cout << "  [-numStages <number_of_stages = " << numStages << ">]" << endl;   //默认20  
    8.  cout << "  [-precalcValBufSize <precalculated_vals_buffer_size_in_Mb = " << precalcValBufSize << ">]" << endl;//默认256  
    9.  cout << "  [-precalcIdxBufSize <precalculated_idxs_buffer_size_in_Mb = " << precalcIdxBufSize << ">]" << endl;//默认256  
    10.  cout << "  [-baseFormatSave]" << endl;                     //是否按照旧版存xml文件默认false  
    11. // cout << "  [-numThreads <max_number_of_threads = " << numThreads << ">]" << endl;//这个参数在3.0版本中才出现,默认numThreads = getNumThreads();  
    12. // cout << "  [-acceptanceRatioBreakValue <value> = " << acceptanceRatioBreakValue << ">]" << endl;//这个参数在3.0版本中才出现,默认-1.0  
    13.  cascadeParams.printDefaults();  
    14.  stageParams.printDefaults();  
    15.  forint fi = 0; fi < fc; fi++ )  
    16.      featureParams[fi]->printDefaults();  

    其中cascadeParams.printDefaults();——cascadeclassifier.cpp 如下

    1. cout << "  [-stageType <";                                                 //默认BOOST  
    2. forint i = 0; i < (int)(sizeof(stageTypes)/sizeof(stageTypes[0])); i++ )  
    3. {  
    4.     cout << (i ? " | " : "") << stageTypes[i];  
    5.     if ( i == defaultStageType )  
    6.         cout << "(default)";  
    7. }  
    8. cout << ">]" << endl;  
    9.   
    10. cout << "  [-featureType <{";                                              //默认HAAR  
    11. forint i = 0; i < (int)(sizeof(featureTypes)/sizeof(featureTypes[0])); i++ )  
    12. {  
    13.     cout << (i ? ", " : "") << featureTypes[i];  
    14.     if ( i == defaultStageType )  
    15.         cout << "(default)";  
    16. }  
    17. cout << "}>]" << endl;  
    18. cout << "  [-w <sampleWidth = " << winSize.width << ">]" << endl;        //默认24*24  
    19. cout << "  [-h <sampleHeight = " << winSize.height << ">]" << endl;  
    stageParams.printDefaults();——boost.cpp如下

    1. cout << "--boostParams--" << endl;  
    2. cout << "  [-bt <{" << CC_DISCRETE_BOOST << ", "  
    3.                     << CC_REAL_BOOST << ", "  
    4.                     << CC_LOGIT_BOOST ", "  
    5.                     << CC_GENTLE_BOOST << "(default)}>]" << endl;                         //默认CC_GENTLE_BOOST   
    6. cout << "  [-minHitRate <min_hit_rate> = " << minHitRate << ">]" << endl;                 //默认0.995  
    7. cout << "  [-maxFalseAlarmRate <max_false_alarm_rate = " << maxFalseAlarm << ">]" << endl;//默认0.5  
    8. cout << "  [-weightTrimRate <weight_trim_rate = " << weight_trim_rate << ">]" << endl;    //默认0.95  
    9. cout << "  [-maxDepth <max_depth_of_weak_tree = " << max_depth << ">]" << endl;           //默认1  
    10. cout << "  [-maxWeakCount <max_weak_tree_count = " << weak_count << ">]" << endl;         //默认100  
    featureParams[fi]->printDefaults();——haarfeatures.cpp 如下

    1. cout << "  [-mode <" CC_MODE_BASIC << "(default)| "  //默认CC_MODE_BASIC  
    2.            << CC_MODE_CORE <<" | " << CC_MODE_ALL << endl;  

    通用参数:

    -data<cascade_dir_name>

    目录名,如不存在训练程序会创建它,用于存放训练好的分类器


    -vec<vec_file_name>

    包含正样本的vec文件名(由 opencv_createsamples 程序生成)


    -bg<background_file_name>

    背景描述文件,也就是包含负样本文件名的那个描述文件


    -numPos<number_of_positive_samples>

    每级分类器训练时所用的正样本数目


    -numNeg<number_of_negative_samples>

    每级分类器训练时所用的负样本数目,可以大于 -bg 指定的图片数目


    -numStages<number_of_stages>

    训练的分类器的级数。


    -precalcValBufSize<precalculated_vals_buffer_size_in_Mb>

    缓存大小,用于存储预先计算的特征值(feature values),单位为MB


    -precalcIdxBufSize<precalculated_idxs_buffer_size_in_Mb>

    缓存大小,用于存储预先计算的特征索引(feature indices),单位为MB。内存越大,训练时间越短


    -baseFormatSave

    这个参数仅在使用Haar特征时有效。如果指定这个参数,那么级联分类器将以老的格式存储


    级联参数:

    -stageType<BOOST(default)>

    级别(stage)参数。目前只支持将BOOST分类器作为级别的类型


    -featureType<{HAAR(default),LBP}>

    特征的类型: HAAR - Haar特征;LBP - 局部纹理模式特征


    -w<sampleWidth>

    -h<sampleHeight>

    训练样本的尺寸(单位为像素)。必须跟训练样本创建(使用 opencv_createsamples 程序创建)时的尺寸保持一致


    Boosted分类器参数:

    -bt<{DAB,RAB,LB,GAB(default)}>

    Boosted分类器的类型: DAB - Discrete AdaBoost,RAB - Real AdaBoost,LB - LogitBoost, GAB - Gentle AdaBoost


    -minHitRate<min_hit_rate>

    分类器的每一级希望得到的最小检测率(正样本被判成正样本的比例)。总的检测率大约为 min_hit_rate^number_of_stages。可以设很高,如0.999


    -maxFalseAlarmRate<max_false_alarm_rate>

    分类器的每一级希望得到的最大误检率(负样本被判成正样本的比例)。总的误检率大约为 max_false_alarm_rate^number_of_stages。可以设较低,如0.5


    -weightTrimRate<weight_trim_rate>

    Specifies whether trimming should be used and its weight. 一个还不错的数值是0.95


    -maxDepth<max_depth_of_weak_tree>

    弱分类器树最大的深度。一个还不错的数值是1,是二叉树(stumps


    -maxWeakCount<max_weak_tree_count>

    每一级中的弱分类器的最大数目。The boosted classifier (stage) will have so many weak trees (<=maxWeakCount), as needed to achieve the given-maxFalseAlarmRate


    Haar特征参数:

    -mode<BASIC(default)| CORE|ALL>

    选择训练过程中使用的Haar特征的类型。 BASIC 只使用右上特征, ALL 使用所有右上特征和45度旋转特征


    5、detectMultiScale函数参数说明

    该函数会在输入图像的不同尺度中检测目标:

    image  -输入的灰度图像,

    objects  -被检测到的目标矩形框向量组,

    scaleFactor  -为每一个图像尺度中的尺度参数,默认值为1.1

    minNeighbors  -为每一个级联矩形应该保留的邻近个数,默认为3,表示至少有3次检测到目标,才认为是目标

    flags -CV_HAAR_DO_CANNY_PRUNING,利用Canny边缘检测器来排除一些边缘很少或者很多的图像区域;

               CV_HAAR_SCALE_IMAGE,按比例正常检测;

               CV_HAAR_FIND_BIGGEST_OBJECT,只检测最大的物体;

               CV_HAAR_DO_ROUGH_SEARCH,只做粗略检测。默认值是0

    minSize和maxSize -用来限制得到的目标区域的范围(先找maxsize,再用1.1参数缩小,直到小于minSize终止检测)


    6、opencv关于Haar介绍

    (haarfeatures.cpp ——opencv3.0)

    Detailed Description

    Haar Feature-based Cascade Classifier for Object Detection

    The object detector described below has been initially proposed by Paul Viola [pdf] and improved by Rainer Lienhart [pdf] .

    First, a classifier (namely a cascade of boosted classifiers working with haar-like features) is trained with a few hundred sample views of a particular object (i.e., a face or a car), called positive examples, that are scaled to the same size (say, 20x20), and negative examples - arbitrary images of the same size.

    After a classifier is trained, it can be applied to a region of interest (of the same size as used during the training) in an input image. The classifier outputs a "1" if the region is likely to show the object (i.e., face/car), and "0" otherwise. To search for the object in the whole image one can move the search window across the image and check every location using the classifier. The classifier is designed so that it can be easily "resized" in order to be able to find the objects of interest at different sizes, which is more efficient than resizing the image itself. So, to find an object of an unknown size in the image the scan procedure should be done several times at different scales.

    The word "cascade" in the classifier name means that the resultant classifier consists of several simpler classifiers (stages) that are applied subsequently to a region of interest until at some stage the candidate is rejected or all the stages are passed. The word "boosted" means that the classifiers at every stage of the cascade are complex themselves and they are built out of basic classifiers using one of four different boosting techniques (weighted voting). Currently Discrete Adaboost, Real Adaboost, Gentle Adaboost and Logitboost are supported. The basic classifiers are decision-tree classifiers with at least 2 leaves. Haar-like features are the input to the basic classifiers, and are calculated as described below. The current algorithm uses the following Haar-like features:

    haarfeatures.png
    image

    The feature used in a particular classifier is specified by its shape (1a, 2b etc.), position within the region of interest and the scale (this scale is not the same as the scale used at the detection stage, though these two scales are multiplied). For example, in the case of the third line feature (2c) the response is calculated as the difference between the sum of image pixels under the rectangle covering the whole feature (including the two white stripes and the black stripe in the middle) and the sum of the image pixels under the black stripe multiplied by 3 in order to compensate for the differences in the size of areas. The sums of pixel values over a rectangular regions are calculated rapidly using integral images (see below and the integral description).

    To see the object detector at work, have a look at the facedetect demo: https://github.com/Itseez/opencv/tree/master/samples/cpp/dbt_face_detection.cpp

    The following reference is for the detection part only. There is a separate application called opencv_traincascade that can train a cascade of boosted classifiers from a set of samples.

    Note

    In the new C++ interface it is also possible to use LBP (local binary pattern) features in addition to Haar-like features. .. [Viola01] Paul Viola and Michael J. Jones. Rapid Object Detection using a Boosted Cascade of Simple Features. IEEE CVPR, 2001. The paper is available online at https://www.cs.cmu.edu/~efros/courses/LBMV07/Papers/viola-cvpr-01.pdf(上述有提到)


    7、opencv关于boost

    (boost.cpp——opencv3.0)

    Boosting

    A common machine learning task is supervised learning. In supervised learning, the goal is to learn the functional relationship  between the input  and the output  . Predicting the qualitative output is called classification, while predicting the quantitative output is called regression.

    Boosting is a powerful learning concept that provides a solution to the supervised classification learning task. It combines the performance of many "weak" classifiers to produce a powerful committee [125] . A weak classifier is only required to be better than chance, and thus can be very simple and computationally inexpensive. However, many of them smartly combine results to a strong classifier that often outperforms most "monolithic" strong classifiers such as SVMs and Neural Networks.

    Decision trees are the most popular weak classifiers used in boosting schemes. Often the simplest decision trees with only a single split node per tree (called stumps ) are sufficient.

    The boosted model is based on  training examples  with  and  .  is a  -component vector. Each component encodes a feature relevant to the learning task at hand. The desired two-class output is encoded as -1 and +1.

    Different variants of boosting are known as Discrete Adaboost, Real AdaBoost, LogitBoost, and Gentle AdaBoost [49] . All of them are very similar in their overall structure. Therefore, this chapter focuses only on the standard two-class Discrete AdaBoost algorithm, outlined below. Initially the same weight is assigned to each sample (step 2). Then, a weak classifier  is trained on the weighted training data (step 3a). Its weighted training error and scaling factor  is computed (step 3b). The weights are increased for training samples that have been misclassified (step 3c). All weights are then normalized, and the process of finding the next weak classifier continues for another  -1 times. The final classifier  is the sign of the weighted sum over the individual weak classifiers (step 4).

    Two-class Discrete AdaBoost Algorithm

    • Set  examples  with  .
    • Assign weights as  .
    • Repeat for  :
      • Fit the classifier , using weights  on the training data.
      • Compute  .
      • Set  and renormalize so that  .
    • Classify new samples x using the formula:  .
    Note
    Similar to the classical boosting methods, the current implementation supports two-class classifiers only. For M > 2 classes, there is theAdaBoost.MH algorithm (described in [49]) that reduces the problem to the two-class problem, yet with a much larger training set.

    To reduce computation time for boosted models without substantially losing accuracy, the influence trimming technique can be employed. As the training algorithm proceeds and the number of trees in the ensemble is increased, a larger number of the training samples are classified correctly and with increasing confidence, thereby those samples receive smaller weights on the subsequent iterations. Examples with a very low relative weight have a small impact on the weak classifier training. Thus, such examples may be excluded during the weak classifier training without having much effect on the induced classifier. This process is controlled with the weight_trim_rate parameter. Only examples with the summary fraction weight_trim_rate of the total weight mass are used in the weak classifier training. Note that the weights for all training examples are recomputed at each training iteration. Examples deleted at a particular iteration may be used again for learning some of the weak classifiers further [49]

    See also
    cv::ml::Boost

    Prediction with Boost

    StatModel::predict(samples, results, flags) should be used. Pass flags=StatModel::RAW_OUTPUT to get the raw sum from Boost classifier.

    8、关于训练过程打印信息的解释

    1)POS count : consumed   n1 : n2

    每次都调用updateTrainingSet( requiredLeafFARate, tempLeafFARate );函数

    1. bool CvCascadeClassifier::updateTrainingSet( double minimumAcceptanceRatio, double& acceptanceRatio)  
    2. {  
    3.     int64 posConsumed = 0, negConsumed = 0;  
    4.     imgReader.restart();  
    5.     int posCount = fillPassedSamples( 0, numPos, true, 0, posConsumed );//Consumed消耗  
    6.     if( !posCount )  
    7.         return false;  
    8.     cout << "POS count : consumed   " << posCount << " : " << (int)posConsumed << endl;//这就是打印信息,我的理解是这个stage判成正样本数和正样本数  
    9.   
    10.     int proNumNeg = cvRound( ( ((double)numNeg) * ((double)posCount) ) / numPos ); // apply only a fraction of negative samples. double is required since overflow is possible  
    11.     int negCount = fillPassedSamples( posCount, proNumNeg, false, minimumAcceptanceRatio, negConsumed );  
    12.     if ( !negCount )  
    13.         return false;  
    14.   
    15.     curNumSamples = posCount + negCount;  
    16.     acceptanceRatio = negConsumed == 0 ? 0 : ( (double)negCount/(double)(int64)negConsumed );  
    17.     cout << "NEG count : acceptanceRatio    " << negCount << " : " << acceptanceRatio << endl;//打印信息,我的理解是  
    18.     return true;  
    19. }  
    1. int CvCascadeClassifier::fillPassedSamples( int first, int count, bool isPositive, double minimumAcceptanceRatio, int64& consumed )  
    2. {  
    3.     int getcount = 0;  
    4.     Mat img(cascadeParams.winSize, CV_8UC1);  
    5.     forint i = first; i < first + count; i++ )  
    6.     {  
    7.         for( ; ; )  
    8.         {  
    9.             if( consumed != 0 && ((double)getcount+1)/(double)(int64)consumed <= minimumAcceptanceRatio )  
    10.                 return getcount;  
    11.   
    12.             bool isGetImg = isPositive ? imgReader.getPos( img ) :  
    13.                                            imgReader.getNeg( img );  
    14.             if( !isGetImg )  
    15.                 return getcount;  
    16.             consumed++;  
    17.   
    18.             featureEvaluator->setImage( img, isPositive ? 1 : 0, i );  
    19.             if( predict( i ) == 1.0F )  
    20.             {  
    21.                 getcount++;  
    22.                 printf("%s current samples: %d\r", isPositive ? "POS":"NEG", getcount);  
    23.                 break;  
    24.             }  
    25.         }  
    26.     }  
    27.     return getcount;  
    28. }  
    1. int CvCascadeClassifier::predict( int sampleIdx )  
    2. {  
    3.     CV_DbgAssert( sampleIdx < numPos + numNeg );  
    4.     for (vector< Ptr<CvCascadeBoost> >::iterator it = stageClassifiers.begin();  
    5.         it != stageClassifiers.end(); it++ )  
    6.     {  
    7.         if ( (*it)->predict( sampleIdx ) == 0.f )  
    8.             return 0;  
    9.     }  
    10.     return 1;  
    11. }  
    1. float CvCascadeBoost::predict( int sampleIdx, bool returnSum ) const  
    2. {  
    3.     CV_Assert( weak );  
    4.     double sum = 0;  
    5.     CvSeqReader reader;  
    6.     cvStartReadSeq( weak, &reader );  
    7.     cvSetSeqReaderPos( &reader, 0 );  
    8.     forint i = 0; i < weak->total; i++ )  
    9.     {  
    10.         CvBoostTree* wtree;  
    11.         CV_READ_SEQ_ELEM( wtree, reader );  
    12.         sum += ((CvCascadeBoostTree*)wtree)->predict(sampleIdx)->value;  
    13.     }  
    14.     if( !returnSum )  
    15.         sum = sum < threshold - CV_THRESHOLD_EPS ? 0.0 : 1.0;  
    16.     return (float)sum;  
    17. }  

    展开全文
  • 利用OpenCv级联分类器实现实时人脸检测

    代码很短,OpenCv很强大。

    import cv2
    face_cascade = cv2.CascadeClassifier('F:\img\haarcascade_frontalface_default.xml')
    '''
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)
    for (x, y, w, h) in faces:
        print(faces)
        cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
    cv2.imshow('img', img)
    cv2.imwrite("F:/img/cyt2.jpg", img)
    cv2.waitKey()
    '''
    cap = cv2.VideoCapture(0)
    while cap.isOpened:
        ret, img = cap.read()
        #转化为灰色图片
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        #检测人脸
        faces = face_cascade.detectMultiScale(gray, 1.3, 5)
        # 框出人脸
        for (x, y, w, h) in faces:
            print("左上角及右下角位置:", [x, y, w, h])
            cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
        cv2.imshow("camera", img)
        if cv2.waitKey(30) & 0xFF == ord('q'):
            bre
    cap.release()
    cv2.destroyAllWindows()
    
    展开全文
  • 级联分类器原理AdaBoost Viola和Jones,2001在CVPR提出; 一种实时对象(人脸)检测框架; 训练速度非常慢,检测速度非常快; 5000个正向人脸样本与300万个非人脸负样本数据。 级联分类器:多个强分类器组合 弱分类器:weak...
  • Haar猫脸检测 haarcascade_frontalcatface.xml haarcascade_frontalcatface_extended.xml ...//猫脸级联分类器 String Cat_fileName = haarcascade_frontalcatface.xml;//猫脸级联分类器 CascadeClassifier
  • 基于OpenCV新版本3.1.0详细讲述了HAAR与LBP级联分类器的基本原理与使用技巧,通过视频中人脸实时检测与眼睛跟踪例子演示了级联分类器在项目中的运用。通过OpenCV自带的训练工具实现样本数据训练生成自己的级联分类器...
  • OpenCV中的HAAR与LBP数据 ...//opencv自带训练好的人脸识别级联器 String Eye_fileName = haarcascade_eye_tree_eyeglasses.xml;//opencv自带训练好的人眼识别级联器 CascadeClassifier face_cascade;//人脸
  • 紧接上一篇文章 opencv 级联分类器训练步骤和方法 级联分类器训练中命令行和训练过程中参数注释:
  • 利用opencv级联分类器进行人脸检测 人脸以及眼睛 基于c++、opencv的人脸检测 1、创建分类器对象 CascadeClassifier face_cascade, eyes_cascade; 2、加载数据的路径 加载本地opencv文件夹自带的xml文件 string face...
  • OpenCV级联分类器训练与使用实战教程 贾志刚 2004毕业于山东大学齐鲁...
  • 训练OpenCV级联分类器 目录结构 . ├─ pos (positive samples database containing .jpg images) │ └── ... ├─ positive (selected positive samples) │ └── ... ├─ random (random images to ...
  • 视频读取 #include #include using namespace std; using namespace cv; String Haar_fileName = haarcascade_frontalface_alt.xml;//Haar String LBP_fileName = lbpcascade_frontalface.xml;...
  • HAAR与LBP的区别(Haar的xml文件大)(LBP的xml文件小) HAAR特征是浮点数计算 LBP特征是整数计算 LBP训练需要的样本数量要比HAAR大 同样的样本空间,HAAR训练出来的数据检测结果要比LBP准确 扩大LBP的样本数据,训练...
  • 使用OpenCV自动的级联分类器训练工具,训练样本数据 得到最终的级联分类器数据(XML格式) 步骤详解 1)收集样本数据 以人脸检测为例:公开的数据库有 正向样本数目(少) 负样本数目(多) 正向样本的大小:统一尺寸 正向...
  • from PIL import Image import os import glob def convertPic(pic, saveDir, width=300, height=300): # 设置宽为210像素,高为425像素(对应宽5.5cm,高11cm) try: img = Image.open(pic) # 读取图片 ...
  • OpenCV级联分类器训练

    2014-02-16 23:47:36
    转自... 检测部分在OpenCV objdetect 模块的文档中有介绍,在那文档中给出了一些级联分类器的基本介绍。这个指南是描述如何训练分类器:准备训练数据和运行训练程序。
  • 使用级联分类器训练人脸模型 项目场景: 作为一个大四狗,在毕业之前想做点有意思的东西,加上人工智能这两年很火,也就从网上找资源,进行了一个学习的过程,使用的平台是QT5.12+OpenCV3.40。目的就是为了训练一...
  • http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guide/ug_traincascade.html#id8 ...opencv中有两个程序可以训练级联分类器opencv_haartraining 和 opencv_traincascade 两者异同: opencv_train...
  • opencv级联分类器(linux系统)

    千次阅读 2019-01-20 17:37:34
    级联分类器这个坑早该挖的了,由于本人之前使用的是win10系统家庭版的某种关系,并没有成功训练出xml,趁着换了Linux和比赛需要就再次挖挖坑,这里用到的是Opencv自带的两个分类器来训练样本,这里仅讲述linux环境下...
  • 是不是就几十的样本不能训练?我有16个正样本25个无关付样本,然后运行train.bat的时候总是有中断,求大神看看什么问题![图片](https://img-ask.csdn.net/upload/201706/27/1498574716_948801.jpg)!...
  • 如下,请问各位老师应该要怎么解决? ![图片说明](https://img-ask.csdn.net/upload/201811/12/1542029356_262265.png)
  • opencv级联分类器训练

    2018-03-26 13:50:09
    4.在下载的opencv文件夹中找到opencv_createsamples.exe和opencv_traincascade.exe这两个exe文件粘贴至训练文件夹 5.如图创建两个bos命令文件.bat用法和cmd命令行相同,优点是可以保存查看 create_vec.bat文件用于...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 802
精华内容 320
关键字:

opencv级联分类器