这段时间在学openCV,准备作一个头部检测,可是openCV自带的分类器只有人脸检测的,并且准确度不高,就准备本身训练一个分类器。在网上看了不少的博客,都讲得不是很清楚,并且全是在windows上训练的,对与用习惯linux的我来讲,用cmd实在是太痛苦了,而我没有在网上找到这方面的博客,甚至连opencv_createsamples和 opencv_traincascade在哪都没说只说在openCV目录下,可是直接安装的openCV下不少是没有的,对于新手来说会很是迷茫,彻底搞不懂。html
而后我就到github上看openCV的仓库,发现仓库的apps目录下有分类器源码,以为能够本身在linux下编译一个训练器python
进过几回尝试,我发现openCV4以上版本源码编译出来是没有我须要的这两个训练器的,3一下版本的会报错,具体什么缘由我不清楚,openCV-3.4.9版本的彻底没有问题linux
sudo apt install cmake
官网:https://cmake.org/filesgit
或者执行命令github
wget https://cmake.org/files/v3.16/cmake-3.16.5-Linux-x86_64.tar.gz
网盘:连接: https://pan.baidu.com/s/1Or1gOkwCozmOTcwKBYErGA 密码: uu89ubuntu
这里我下载的是cmake-3.16.5-Linux-x86_64windows
解压:tar zxvf cmake-3.16.5-Linux-x86_64.tar.gz 缓存
移到opt目录下:mv cmake-3.16.5-Linux-x86_64 /optapp
创建软链接:ln -s /opt/cmake-3.16.5-Linux-x86_64/bin/* /usr/binide
检测安装是否成功:
cmake --version
cmake version 3.16.5
CMake suite maintained and supported by Kitware (kitware.com/cmake).
github地址:https://github.com/opencv/openc
网盘地址:连接: https://pan.baidu.com/s/11drQWD-EjKVHwKmaNk4aRA 密码: qfuf
我编译好的:连接: https://pan.baidu.com/s/1STu5cLtAWIkaEns5eVTzOA 密码: swmw
下面的步骤已经在Ubuntu10.04上测试过了,可是也能够在其余发行版上使用。
必需的包
GCC 4.4.x 或更新
CMake 2.8.7 或更高版本
Git
GTK+2.x 或更高版本, including 头 (libgtk2.0-dev)
pkg-config
Python 2.6或更高版本以及带有开发人员包的Numpy 1.5或更高版本(Python -dev, Python - Numpy)
ffmpeg或libav开发包:libavcodec-dev,libavformat-dev,libswscale-dev
[可选] libtbb2 libtbb-dev
[可选] libdc1394 2.x
[可选] libjpeg-dev, libpng-dev, libtiff-dev, libjasper-dev, libdc1394-22-dev
[可选] CUDA Toolkit 6.5 or higher
sudo add-apt-repository "deb http://security.ubuntu.com/ubuntu xenial-security main"
sudo apt-get install build-essential
# 若是安装了cmake 和git 的能够删下面的选项
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev
解压:unzip mirrors-opencv-3.4.9.zip
cd opencv
mkdir build # 编译会生成不少文件,最好建一个文件夹来保存
cd build
cmake ../ # 生成makefile
make # 使用makefile编译 时间会很长,二十分钟的样子
编译好后就能够找咱们须要的训练器了
cd build/bin # 这样就能够看见了
建立pos目录装正样本
正负样本都要转化成灰度图,并且对于正样本用haar特征训练是规格化成20×20或其余大小,最好不要太大,过多的haar特征会影响分类器的训练时间;对于LBP特征正样本要规格化为24×24大小,而对于HOG要规格化成64×64. 负样本对尺寸没有统一要求,在训练对应的分类器时,选择的负样本尺寸必定要大于等于正样本规定的尺寸。
建立neg目录装负样本
负样本有两点要求:1)不能包含正样本且尽量多的提供场景的背景图;2)负样本尽量的多,并且要多样化,和正样本有必定的差距可是差异也不要太大,不然容易在第一级就所有被分类器reject,训练时不能显示负样本的个数,从而致使卡死。
建立xml目录装训练数据
将训练器opencv_createsamples opencv_traincascade拷贝到当前路径下
ls -rt pos > pos.txt # pos.txt 正样本相对路径表
ls -rt neg > neg.txt # neg.txt 负样本相对路径表
修改pos.txt和neg.txt
gedit pos.txt
Ctrl + A 全选 ,而后按Tab 键
选一个空格
选择查找替换
所有替换,neg.txt的这一步替换长neg/
pos.txt还须要多一步,不然会报错,1 表明个数 0 0 表明照片的起点坐标,50 50 为个人照片的大小
./opencv_createsamples -info pos.txt -vec pos.vec -bg neg.txt -num 2874 -w 50 -h 50
以上参数的含义以下: -vec <vec_file_name>:训练好的正样本的输出文件名。 -img<image_file_name>:源目标图片 -bg<background_file_name>:背景描述文件。 -num<number_of_samples>:要产生的正样本的数量,和正样本图片数目相同。 -bgcolor<background_color>:背景色。背景色制定了透明色。对于压缩图片,颜色方差量由bgthresh参数来指定。则在bgcolor-bgthresh 和bgcolor+bgthresh 中间的像素被认为是透明的。 -bgthresh<background_color_threshold>
-inv:若是指定,颜色会反色 -randinv:若是指定,颜色会任意反色 -maxidev<max_intensity_deviation>:背景色最大的偏离度。 -maxangel<max_x_rotation_angle>, -maxangle<max_y_rotation_angle>, -maxzangle<max_x_rotation_angle>:最大旋转角度,以弧度为单位。 -show:若是指定,每一个样本会被显示出来,按下"esc"会关闭这一开关,即不显示样本图片,而建立过程 继续。这是个有用的debug 选项。 -w<sample_width>:输出样本的宽度(以像素为单位) -h<sample_height>:输出样本的高度(以像素为单位)
只须要对正样本进行以上操做,负样本不须要生成vec文件。。。
注意:这里要找一台好一点的电脑训练,我训练一万的样本,从最开始一天训练一级,而后每级的时间增长半天,到第五级已经差很少须要三天了,预计到20级没一两月搞不定
./opencv_traincascade -data xml -vec pos.vec -bg neg.txt -numPos 2000 -numNeg 7370 -numStages 20 -featureType HAAR -w 50 -h 50
# 注意大小写,写错可能不会报错,可是识别不了,就会使用默认值,这里我就被坑过
# 训练时间会很是很是长,我第一次用了198正样本、368负样本就训练了一个晚上,第二次用两千多的正样本,三千多的负样本就更长了,可是训练中途断了再执行命令时会继续上一次训练
# 注意 :这里的-numPos *** 必定要比 准备.vec文件时的 -num *** 小,不然在训练时可能会报错,显示找不到更多正样本
像我这里输入-numPos 2000 ,在训练到第三级时就须要2018个正样本,若是.vec里只有2000个就会找不到新的正样本,从而报错
以上参数的含义以下:
-data <cascade_dir_name>:目录用于保存训练产生的分类器xml文件和中间文件,如不存在训练程序会建立它;
-vec <vec_file_name>:由 opencv_createsamples 程序生成的包含正样本的vec文件名;
-bg <background_file_name>:背景描述文件,也就是包含负样本文件名的那个描述文件
-numPos <number_of_positive_samples>:每级分类器训练时所用的正样本数目(默认值为2000); -numNeg <number_of_negative_samples>:每级分类器训练时所用的负样本数目,能够大于 -bg 指定的图片数目(默认值为1000);
-numStages <number_of_stages>:训练的分类器的级数(默认值为20级);
-precalcValBufSize <precalculated_vals_buffer_size_in_Mb>:缓存大小,用于存储预先计算的特征值(feature values),单位为MB(默认值为256); -precalcIdxBufSize <precalculated_idxs_buffer_size_in_Mb>:缓存大小,用于存储预先计算的特征索引(feature indices),单位为MB(默认值为256);
内存越大,训练时间越短。 -baseFormatSave:这个参数仅在使用Haar特征时有效。若是指定这个参数,那么级联分类器将以老的格式存储(默认不指定该参数项,此时其值为false;一旦指定则其值默认为true);
级联参数:CvCascadeParams类,定义于cascadeclassifier.h -stageType <BOOST(default)>:级别(stage)参数。目前只支持将BOOST分类器做为级联的类型; -featureType<{HAAR(default), LBP}>:特征的类型: HAAR - 类Haar特征; LBP - 局部纹理模式特征(默认Harr); -w <sampleWidth>:训练样本的宽(单位为像素,默认24); -h <sampleHeight>:训练样本的高(单位为像素,默认24); 训练样本的尺寸必须跟训练样本建立(使用 opencv_createsamples 程序建立)时的尺寸保持一致。
Boosted分类器参数:CvCascadeBoostParams类,定义于boost.h -bt <{DAB, RAB, LB, GAB(default)}>:Boosted分类器的类型(DAB - Discrete AdaBoost, RAB - Real AdaBoost, LB - LogitBoost, GAB - Gentle AdaBoost为默认); -minHitRate <min_hit_rate>:分类器的每一级但愿获得的最小检测率(默认值为0.995),总的检测率大约为 min_hit_rate^number_of_stages; -maxFalseAlarmRate <max_false_alarm_rate>:分类器的每一级但愿获得的最大误检率(默认值为0.5),总的误检率大约为 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>:每一级中的弱分类器的最大数目(默认值为100)。The boosted classifier (stage) will have so many weak trees (<=maxWeakCount), as needed to achieve the given -maxFalseAlarmRate;
最后等一夜就能够获得训练的分类器了,cascade.xml就是咱们的分类器
最后放上个人分类器连接
包含训练5级的分类器和训练15级的分类器,效果不是很好
连接: https://pan.baidu.com/s/17U3cGaZdGj6glBeWJThtLA 密码: oc5b
import cv2
face = cv2.CascadeClassifier("./data/cascade.xml") #人脸识别
cap = cv2.VideoCapture(2)
while True:
ret, img = cap.read()
roi_color = 0
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #转换为灰度图片,haar特征都是在灰度上检测
faces = face.detectMultiScale(gray,1.3,5) #参数1:灰度图片数据 2:缩放比例 3:人脸大小不能小于5个像素
# 获取宽高信息,我的脸画方框
for (x,y,w,h) in faces:
# img:要画的图片,(x,y):起始坐标 ,(x+w,y+h):宽高,颜色,线条宽度
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
cv2.imshow('10',img)
if cv2.waitKey(5) & 0xff == ord("q"):
break
cap.release()
cv2.destroyAllWindows()