opencv_traincascade训练人脸检测

首次学习使用opencv的opencv_traincascade来训练级联分类器,特做记录。
首先是准备正负样本,正样本我准备了1486张64*64的人脸图片,负样本随意寻找了3000张图片,不包含人脸。

工程如下:
opencv_traincascade训练人脸检测_第1张图片

data–存放训练出来的数据
neg-背景图片
pos-人脸图片
test-用于测试的图片

准备负样本

将3000张负样本图片放入neg目录下,
进入neg目录,执行dir /b > neg.txt
得到neg.txt文件:

neg-0002.jpg
neg-0003.jpg
neg-0004.jpg
neg-0005.jpg
neg-0006.jpg
neg-0007.jpg
neg-0009.jpg
neg-0010.jpg
...

这样发现无法训练,因为可执行未见和负样本不在同一个目录,所以又使用UE编辑器的列块模式,在所有条目前面加了neg/,最后记得删掉最后一行–一般是文件名

neg/neg-0002.jpg
neg/neg-0003.jpg
neg/neg-0004.jpg
neg/neg-0005.jpg
neg/neg-0006.jpg
neg/neg-0007.jpg
neg/neg-0009.jpg
neg/neg-0010.jpg
...

准备正样本

将1486张64*64的人脸图片放入pos目录下,
进入pos目录,执行dir /b > pos.txt
得到pos.txt文件:

fd_001_1.jpg  
fd_001_2.jpg 
fd_002_1.jpg  
fd_002_2.jpg 
fd_003_1.jpg 
fd_003_2.jpg
fd_004_1.jpg 
... 

我们必须给每一个图片添加描述信息:
图片中有几个人脸 人脸开始的位置(左上角) 人脸结束的位置(右下角)
1 (0,0) (64,64)

因此,pos.txt变为这样:

fd_001_1.jpg  1 0 0 64 64  
fd_001_2.jpg  1 0 0 64 64  
fd_002_1.jpg  1 0 0 64 64  
fd_002_2.jpg  1 0 0 64 64  
fd_003_1.jpg  1 0 0 64 64  
fd_003_2.jpg  1 0 0 64 64  
fd_004_1.jpg  1 0 0 64 64  
...

最后记得删掉最后一行–一般是文件名

可能是为了加快训练的速度,需要把训练的输入数据写入一个.vec文件中,这就用opencv_createsamples.exe了。

生成样本

opencv_createsamples.exe  -info pos/pos.txt -bg neg/neg.txt -w 64 -h 64 -num 1486 -vec pos.vec

上述命令结果如下:

Info file name: pos/pos.txt
Img file name: (NULL)
Vec file name: pos.vec
BG  file name: neg/neg.txt
Num: 1486
BG color: 0
BG threshold: 80
Invert: FALSE
Max intensity deviation: 40
Max x angle: 1.1
Max y angle: 1.1
Max z angle: 0.5
Show samples: FALSE
Width: 64
Height: 64
Max Scale: -1
Create training samples from images collection...
Done. Created 1486 samples

提示成功生成1486个samples了,接下来就可以训练了。

训练

opencv_traincascade.exe  -data data -vec pos.vec -bg neg/neg.txt -numPos 500 -numNeg 2000 -numThreads 10 -featureType LBP -w 64 -h 64 -minHitRate 0.95 -numStages 16

可以看到,我只使用了500个正样本(我想这样可能会快一点),2000个负样本(网上说正负样本1:4比较合理),另外我指定的特征为LBP,默认的是HAAR哦,-w -h指定图片的宽高,minHitRate 是做小命中率,numStages 指定为16,如果这个值比较小,比如6,就会很容易出现如下问题:

Required leaf false alarm rate achieved. Branch training terminated.

这个时候你把numStages 改大一些,然后发现又可以训练了。

测试

训练到Stages为12的时候,不小心退出了,索性测试下,能不能识别:
测试代码如下:

#include   
#include   
#include   
#include   
#include "wininet.h"  
#include   
#include   
#include   
#pragma comment(lib,"Wininet.lib")  


#include "opencv2/objdetect/objdetect.hpp"  
#include "opencv2/highgui/highgui.hpp"  
#include "opencv2/imgproc/imgproc.hpp"  
#include "opencv2/ml/ml.hpp"  

#include   
#include   

using namespace std;
using namespace cv;

String cascadeName = "F:\\work\\ml\\face-rec\\data\\cascade.xml";//训练数据  
//String cascadeName = "haarcascade_frontalface_alt2.xml";//训练数据  
int main()
{
    CascadeClassifier cascade;//创建级联分类器对象  
    vector rects;
    vector::const_iterator pRect;

    double scale = 1.;

    double t;
    if (!cascade.load(cascadeName))//从指定的文件目录中加载级联分类器  
    {
        cerr << "ERROR: Could not load classifier cascade" << endl;
        return 0;
    }

    Mat smallImg = imread("bc.jpg");

    rects.clear();
    printf("begin...\n");
    t = (double)cvGetTickCount();//用来计算算法执行时间  
    cascade.detectMultiScale(smallImg, rects, 1.1, 2, 0,Size(10,10),Size(400, 400));
    //|CV_HAAR_FIND_BIGGEST_OBJECT//|CV_HAAR_DO_ROUGH_SEARCH|CV_HAAR_SCALE_IMAGE,  

    t = (double)cvGetTickCount() - t;
    printf("detection time = %g ms\n\n", t / ((double)cvGetTickFrequency()*1000.));
    for (pRect = rects.begin(); pRect != rects.end(); pRect++)
    {
        rectangle(smallImg, cvPoint(pRect->x, pRect->y), cvPoint(pRect->x + pRect->width, pRect->y + pRect->height), cvScalar(0, 255, 0));
    }

    imshow("result",smallImg);
    waitKey(0);
    return 0;
}

测试中,我分别使用了自己训练的分类器和opencv自带的分类,发现还是opencv自带的明显好一些。
opencv_traincascade训练人脸检测_第2张图片

这张图片是使用我训练出来的参数识别数来的人脸,在脸比较正的时候,识别出来的概率还蛮大的。

这张也是脸比较正的,也能识别,但是左下角的绿色方块是什么鬼?

opencv_traincascade训练人脸检测_第3张图片

像这样环境比较杂乱的就完全乱了…

你可能感兴趣的:(ml)