Opencv+traincasade训练器训练
1. 前期准备
- opencv3.4.1 +VS2018
- 存放正样本和负样本的文件夹
- 生成训练的文件
2. 准备样本
2.1 准备正样本
正样本就是你想要识别的物体,可根据情况选择样本的多少(实际上越多越好),样本之间不要重 复,差异性越大越好(比如人脸识别,就拍很多张正脸,侧脸之类的)。尺寸看情况选择,但是必须归一化,即统一尺寸。本文中选择的尺寸为128X96,越大的尺寸训练起来会越慢。
2.2 准备负样本
负样本就是背景,拍照时你所要识别的物体的背景,每个项目都有每个项目不同的负样本,最好不要随意找一些无关的图片做负样本,这样会导致训练效果很差。尺寸不需要归一化,但是必须大于或等于正样本的尺寸。正负样本比例最好是1:3或者更大。
3. 生成训练的文件
在你自己的文件夹中,新建pos文件夹用来存放正样本图片,neg文件夹存放负样本文件夹,xml文件夹存放训练生成的xml文件。然后在自己安装的opencv的库中将opencv_createsamples.exe和 opencv_traincascade.exe复制在文件里面。这俩个文件在 E:\opencv\build\x64\vc14\bin 文件里面。(注:这里是我的opencv文件夹)
之后的操作便是在DOS界面里完成:
打开dos界面,找到你自己的上文中的文件,打开pos文件夹,输出dir /b >pos.txt生成pos.txt文件
dir /b >pos.txt
如图所示
生成了文件之后在pos文件中打开生成的pos.txt文件,然后删除pos.txt
一键替换jpg后缀:
将jpg替换成jpg 1 0 0 128 96
1 是这个图片中只有一个识别对象
0 0 是这个图像的起始坐标
128 96是你设定的图片大小
然后在最后一行删除pos.txt字样
同样的操作在neg文件中生成neg.txt文件
接下来的操作和pos.txt有点不一样,打开neg.txt文件,不需要修改jpg后缀,但是需要在图片名字前面加入路径,否则opencv无法识别。(记住一定是\ \号!!)
然后在最后一行删除neg.txt字样。
然后在dos界面回到你的文件目录下,生成pos.vec文件,输入
opencv_createsamples.exe -vec pos.vec -info pos\pos.txt - w 128 -h 96 -num 28
-vec 是生成pos.vec文件
-info 是pos.txt文件的相对路径
-w -h 是正样本的图片大小
-num 是正样本的图片数量
然后输入 ,生成XML文件
opencv_traincascade.exe -data xml -vec pos.vec -bg neg/neg.txt -numPos 28 -numNeg 1500 -minHitRate 0.9999 -maxFalseAlarmRate 0.5 -featureType LBP -numStages 10 -w 128 -h 96
参数说明
-data <cascade_dir_name>
目录名,如不存在训练程序会创建它,用于存放训练好的分类器。
-vec <vec_file_name>
包含正样本的vec文件名(由 opencv_createsamples 程序生成)。
-bg <background_file_name>
背景描述文件,也就是包含负样本文件名的那个描述文件。
-numPos <number_of_positive_samples>
每级分类器训练时所用的正样本数目。其指设置为正样本数量的85%(这是一个保守值)。具体的也要根据级联器的层数来决定的。因为每个stages都是会增加图片数量来进行分类。
-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
-h
训练样本的尺寸(单位为像素)。必须跟训练样本创建(使用 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。总检测率即为整个级联器的检测召回率,
-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.
类Haar特征参数:
-mode <BASIC (default) | CORE | ALL>
选择训练过程中使用的Haar特征的类型。 BASIC 只使用右上特征, ALL 使用所有右上特征和45度旋转特征。
4. 等待生成XML文件
输出完上文的执行命令后会出现
等待完成就可以了
完成了之后,就可以在opencv中引用在xml文件夹中生成的cascade.xml文件去做识别了。
#include "pch.h"
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <stdio.h>
using namespace std;
using namespace cv;
string face_name = "D:\\study\\my_face_train\\xml\\cascade.xml";
CascadeClassifier face;
RNG rng(12345);
void detectface(Mat frame);
int main()
{
VideoCapture capture(0);
if (!face.load(face_name))
{
printf("--(!)Error loading\n");
return -1;
}
while (1)
{
Mat frame;
capture >> frame;
resize(frame, frame, Size(frame.cols / 2, frame.rows / 2), 0, 0, INTER_LINEAR);//图片缩放
detectface(frame);
waitKey(1);
}
}
void detectface(Mat frame)
{
vector<Rect>faces;
Mat frame_gray;
cvtColor(frame, frame_gray, CV_BGR2GRAY);//灰度图像
equalizeHist(frame_gray, frame_gray);//直方分布均衡化
face.detectMultiScale(frame_gray, faces, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(0, 0));//分类器识别
for (int i = 0; i < faces.size(); i++)
{
Point center(faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5);
rectangle(frame, Rect(faces[i].x, faces[i].y, faces[i].width*0.5, faces[i].height*0.5),Scalar(0, 255, 0), 2);
}
imshow("frame", frame);
}