最近在做一个小项目,要训练自己的分类器,网上找了很多资料,但是没有很详细的,这里我将我做的过程,详细的总结一下,一来给大家总结经验,二来日后好查阅,原理我就不赘述,直接讲一下如何训练
一:图片的处理
做训练的图片要是灰度图,而且要统一大小,所以我就用python做了灰度化和归一化处理,代码如下:
from skimage import io,transform,color
import numpy as np
def convert_gray(f,**args):#图片处理与格式化的函数
rgb=io.imread(f) #读取图片
gray=color.rgb2gray(rgb) #将彩色图片转换为灰度图片
dst=transform.resize(gray,(40,40)) #调整大小,图像分辨率为40*40
return dst
datapath='D:/Face_Program/neg/' #图片所在的路径
str=datapath+'/*.jpg' #识别.jpg的图像
coll = io.ImageCollection(str,load_func=convert_gray)#批处理
for i in range(len(coll)):
io.imsave(r'D:/Face_Program/neg1//'+np.str(i)+'.jpg',coll[i]) #保存图片在d:/daate/date/人;
处理好图片后,我们就要开始训练了
二 生成可描述文件
在opencv的安装目录中的bin文件夹下有两个可执行文件opencv_createsamples.exe和opencv_traincascade.exe。将这两个文件拷贝到训练文件夹下,并将正、负样本的文件夹和描述文件——positive_samples.txt和negative_samples.txt也拷贝到这个文件夹下。同时,新建两个.bat文件——create_positive_samples.bat和traincascade.bat,新建一个文件夹data,data文件夹是用于存放之后训练完的数据。这样,训练目录如下:
我会把这个opencv文件放在后面,需要的自己下载
然后使用editplus打开生成的文本文件positive_samples.txt 使用快捷键Ctrl+H打开Replace
1.在行首填充所需字符
这里说明一下,图像处理成多少尺寸,生成描述文件的时候就是多少尺寸,我之间生成的是64*64的,但是训练的时候很慢我就改成40/840的了,正样本要有尺寸信息,负样本不需要。上面步骤是做的笔记现在保存退出,制作正样本
三 制作正样本
然后右键create_positive_samples.bat文件
其中,-info字段填写正样本描述文件;-vec用于保存制作的正样本;-num制定正样本的数目;-w和-h分别指定正样本的宽和高。
保存,双击这个文件,开始制作正样本:
这样,正样本制作完成了
四 级联分类器训练
下面进行级联分类器的训练,在traincascade.bat中输入如下内容
字段说明如下:
-data:指定保存训练结果的文件夹;
-vec:指定正样本集;
-bg:指定负样本的描述文件夹;
-numPos:指定每一级参与训练的正样本的数目(要小于正样本总数);
-numNeg:指定每一级参与训练的负样本的数目(可以大于负样本图片的总数);
-numStage:训练的级数;
-w:正样本的宽;
-h:正样本的高;
-minHitRate:每一级需要达到的命中率(一般取值0.95-0.995);
-maxFalseAlarmRate:每一级所允许的最大误检率;
-mode:使用Haar-like特征时使用,可选BASIC、CORE或者ALL;
numPos和numNeg要满足1:2.5-1:3之间,这个我自己也把握不好,只有自己慢慢试了,numStage一般在15-20之间,具体还是得靠自己把握,由于样本数不够或者内存等其他原因,训练层数达不到我们的结果,训练到一半就完成了,此时分类器还是可以用的,只是效果可能不太好,比如我自己最多只训练到第八层
另外,还可指定以下字段:
-featureType:可选HAAR或LBP,默认为HAAR;
其他字段将不再说明。
保存,双击执行,开始漫长的训练过程(训练可中断,中断后再执行,会继续中断前的训练
训练结束后,data文件夹下会生成如下训练结果
cascade.xml文件即为最终的训练结果,即可拿来进行目标检测,通过上述方法,可以训练自己的分类器哦
测试如下,在一段视频中检测目标
import cv2
import sys
from PIL import Image
def CatchUsbVideo(window_name, camera_idx):
cv2.namedWindow(window_name)
#视频来源,可以来自一段已存好的视频,也可以直接来自USB摄像头
cap = cv2.VideoCapture(camera_idx)
#告诉OpenCV使用人脸识别分类器
classfier = cv2.CascadeClassifier("D:\\Face_Program\\data4_8\\cascade.xml")
#识别出人脸后要画的边框的颜色,RGB格式
color = (0, 255, 0)
while cap.isOpened():
ok, frame = cap.read() #读取一帧数据
if not ok:
break
#将当前帧转换成灰度图像
grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#人脸检测,1.2和3分别为图片缩放比例和需要检测的有效点数
faceRects = classfier.detectMultiScale(grey, scaleFactor = 1.2, minNeighbors = 3, minSize= (40,40))
if len(faceRects) > 0: #大于0则检测到
for faceRect in faceRects: #单独框出每一张
x, y, w, h = faceRect
cv2.rectangle(frame, (x - 20, y - 20), (x + w + 10, y + h + 10), color, 2)
#显示图像
cv2.imshow(window_name, frame)
c = cv2.waitKey(10)
if c & 0xFF == ord('q'):
break
#释放摄像头并销毁所有窗口
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
if len(sys.argv) != 1:
print("Usage:%s camera_id\r\n" % (sys.argv[0]))
else:
CatchUsbVideo(" recognition region", 0)
希望能对大家有所帮助,有所启发