本文中简单介绍使用opencv的createsamples和traincascade生成自己的分类器以及借用python的opencv库实现人脸图像采集、人脸识别
使用opencv训练自己的级联分类器&python人脸识别
训练级联分类器
首先需要在自己的电脑或服务器上安装
opencv
,这里需要用到opencv_createsamples
和opencv_traincascade
,opencv版本我这里安装的是stable 3.4.14版本,据说是4之后的版本不会内置这两个工具,所以选择的V3。opencvhaartraining属于旧版本程序,仅支持Haar特征,而opencvtraincascade同时支持Haar和LBP特征,且LBP属于整数特征,速度更快。(当然了,默认的opencv_traincascade仅使用的是多线程来处理的,如果想进一步使用多进程来提高速度,可以使用TBB来重新编译traincascade)。
至于为什么是整数特征,这里只简单的介绍一下:此模式是通过找到图像的局部特征,通过每个像素与相邻像素比较来实现(他会用一个3*3的窗口在图片上进行移动,每次移动时将周边元素的像素值和中心元素的像素值进行比较,小于等于中心值的记为1,反之则为0,然后在这个窗口内进行顺时针读取,得到0101的二进制数,以此来代表并区分不同的特征)。
我这里使用的brew
安装的
brew search opencv
brew install opencv@3
echo 'export PATH="/opt/homebrew/opt/opencv@3/bin:$PATH"' >> ~/.zshrc
至此完成opencv的安装,之后就可以继续后面的工作了。
准备样例
这里我们需要分别准备正向与反向样例(为了分类器的准确性,条件允许的话可以设置尽可能多的正向样例,以及多倍于正向的反向样例,以提高识别的准确性) 项目结构如下
. ├── neg.txt ├── pos.dat ├── pos.vec ├── to_gray.py ├── to_jpg.py ├── training-files │ ├── neg │ ├── neg_gray │ ├── neg_jpg │ ├── pos │ └── pos_gray └── xml ├── cascade.xml ├── params.xml ... └── stage9.xml
neg和pos里分别为正向与反向的样例文件,这里全部转化为灰度图来使用,转灰度图可使用以下代码来实现
# -*- coding:utf-8 -*- import os import cv2 def img2Gray(): path = "./training-files/neg_jpg/" new_path = "./training-files/neg_gray/" i = 0 for filename in os.listdir(path): img = cv2.imread(path + filename) img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) i += 1 tmp = str.split(filename, '.') # new_name = tmp[0] + "_gray.jpg" new_name = str(i) + "_gray.jpg" cv2.imwrite(new_path + new_name, img) # cv2.waitKey(0) & 0xFF if __name__ == '__main__': img2Gray()
pos.dat为正向样例描述文件,内容如下,包括文件名,目标个数,以及目标的(x,y,w,h),以图片左上角为零点,目标起始位置的x与y的坐标,目标宽度和高度
反向样例的描述文件只需列出文件名(包含文件路径)即可
usage
Usage: opencv_createsamples [-info <collection_file_name>] [-img <image_file_name>] [-vec <vec_file_name>] [-bg <background_file_name>] [-num <number_of_samples = 1000>] [-bgcolor <background_color = 0>] [-inv] [-randinv] [-bgthresh <background_color_threshold = 80>] [-maxidev <max_intensity_deviation = 40>] [-maxxangle <max_x_rotation_angle = 1.100000>] [-maxyangle <max_y_rotation_angle = 1.100000>] [-maxzangle <max_z_rotation_angle = 0.500000>] [-show [<scale = 4.000000>]] [-w <sample_width = 24>] [-h <sample_height = 24>] [-maxscale <max sample scale = -1.000000>] [-rngseed <rng seed = 12345>]
生成vec文件
opencv_createsamples -vec pos.vec -info pos.dat -num 17 -w 40 -h 40
,这里的参数分别为输出的文件名、描述文件名、样例数量、输出宽以及高接下来可以使用
opencv_createsamples -vec pos.vec -w 40 -h 40
查看输出的样例最后使用以下命令生成分类器的xml文件
opencv_traincascade -data xml -vec pos.vec -bg neg.txt -numPos 17 -numNeg 53 -numStages 20 -w 40 -h 40 -featureType LBP -precalcValBufSize 4096 -precalcldxBufSize 4096 -maxWeakCount 200 -minHitRate 0.999 -maxFalseAlarmRate 0.2 -data 指定输出文件目录 -vec 指定正向样例描述文件 -bg 指定反向样例描述文件 -numPos 正向样例数量 -numNeg 反向样例数量 -numStages 训练的分类器的级数 -w -h 宽高 -featureType 特征类别 (LBP、HOG、Haar)推荐使用LBP 整数类型,速度更快,精度略差于Haar -precalcValBufSize 缓存大小,用于存储预先计算的特征值(feature values),单位为MB,默认1024MB -precalcldxBufSize 缓存大小,用于存储预先计算的特征索引(feature indices),单位为MB,默认1024MB。内存越大,训练时间越短 -maxWeakCount 每一级中的弱分类器的最大数目,默认100。增强的分类器(stage)将有许多弱树(<=maxWeakCount),这是实现给定-maxFalseAlarmRate所需要的。 -minHitRate 分类器的每一级希望得到的最小检测率,默认0.995。总的检测率大约为 min_hit_rate^number_of_stages - maxFalseAlarmRate 分类器的每一级希望得到的最大误检率,默认0.5。总的误检率大约为 max_false_alarm_rate^number_of_stages 。在使用LBP特征参数训练时推荐设置成0.2甚至更小
至此,就可以生成自己的分类器了!
测试分类器
采集人脸数据
这里需要用到cv2和numpy库, 可以使用pip安装
# 加载生成的xml文件 face_cascaded = cv2.CascadeClassifier('/Users/lhui/codes/python/haarcascade_frontalface_default.xml') # 打开摄像头 camera = cv2.VideoCapture(0) cv2.namedWindow('Dynamic') count = 1 while True: ret, frame = camera.read() if ret: # 转换为灰度图 gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 人脸检测 face = face_cascaded.detectMultiScale(gray_img, 1.3, 5) for (x, y, w, h) in face: # 在原图上绘制矩形 cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2) # 调整图像大小 new_frame = cv2.resize(frame[y:y + h, x:x + w], (92, 112)) cv2.imwrite('%s/%s.png' % (path, str(count)), new_frame) count += 1 cv2.imshow('Dynamic', frame) if cv2.waitKey(100) & 0xff == ord('q'): break camera.release() cv2.destroyAllWindows()
图像校验
# 加载训练的数据 X, y, names = load_images(data) print(X, y, names) print('x', X) model = cv2.face.EigenFaceRecognizer_create() model.train(X, y) camera = cv2.VideoCapture(0) cv2.namedWindow('Dynamic') # 创建级联分类器 face_cascaded = cv2.CascadeClassifier('/Users/lhui/codes/python/haarcascade_frontalface_default.xml') while True: ret, frame = camera.read() # 判断图像是否读取成功 if ret: # 转换为灰度图 gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 利用级联分类器鉴别人脸 faces = face_cascaded.detectMultiScale(gray_img, 1.3, 5) for (x, y, w, h) in faces: frame = cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2) # 蓝色 roi_gray = gray_img[y:y + h, x:x + w] try: roi_gray = cv2.resize(roi_gray, (92, 112), interpolation=cv2.INTER_LINEAR) params = model.predict(roi_gray) cv2.putText(frame, names[params[0]], (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2) except: continue cv2.imshow('Dynamic', frame) # 按下q键退出 if cv2.waitKey(100) & 0xff == ord('q'): break camera.release() cv2.destroyAllWindows()