后面有详细解释,和步骤代码的实现,可能需要简单修改,建议代码自己先写着试试
训练步骤下载文件包opencv
。这里的opencv
是指编译好的.exe
文件,不是需要编译的source
源码文件。建议下载3.4
版本的,最新版可能训练步骤不同,这里我没有做仔细学习,毕竟新手,等以后熟练了再做解释。
windows版本:官网下载
iOS版本:官网下载
Android版本:官网下载
官网地址:https://opencv.org/releases/
但是有一点,官网嘛,外网比较慢,我下载了一晚上,也可以去csdn下载,就是需要金币,不太值。
样本收集
样本收集是个费时费力的活,当时在朋友圈喊了一声,同学把淘宝弄来的给我了,实际上符合条件的还是不够用的,所以大家可以找找其他图片。
样本分为正负样本集。
**正样本:**人脸图像,数量在一般在2k以上
**负样本:**非人脸任何图像,数量一般在5k以上
正负样本越多越好,当然,负样本要远大于正样本数量。
准备文件夹
这一步好说,让准备文件夹,主要是命令和文件夹有关,所以这一步要求大家和我准备一样的文件夹,如果你熟悉命令可以另说。
G:\opencv\build\x64\vc15\bin
,把它复制粘贴到cascade文件夹
下
opencv_creaesamples.exe:该文件存放路径同上
opencv_traincascade.exe:该文件存放路径同上
xml文件夹:用于存放训练好的.xml
文件
人脸图像一张:用于后期测试
修改正负样本照片
正样本:
修改成灰度图
大小:Haar特征2020;LBP特征2424
数量:2000以上
负样本:
修改成灰度图
大小:60*60
数量:5000以上
若样本直接修改可能会造成图片扭曲,因为图片不一定是n*n
,可能是n*m
的。
分别在pos文件夹
和neg文件夹
下添加.txt
文件pos.txt
和neg.txt
。然后,八仙过海,各显神通,将文件填充如下:1 0 0 20 20
写入文件dir/b > pos.txt
注意:将文件末尾的多余字符neg.txt和pos.txt删掉
开始生成pos.vec
文件,进入cascade文件夹
中,输入命令:
opencv_createsamples.exe -info pos\pos.txt -vec pos.vec -bg neg\neg.txt -num 2000 -w 20 -h 20
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-19M8Un7G-1586010263150)(leanote://file/getImage?fileId=5e888aac8540084b17000002)]
开始训练:opencv_traincascade.exe -data xml -vec pos.vec -bg neg\neg.txt -numPos 2000 -numNeg 5000 -numStages 20 -featureType HAAR -w 20 -h 20
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4WqVbf45-1586010263150)(leanote://file/getImage?fileId=5e888b4c8540084b17000003)]
我电脑没有显卡,不知道这个训练吃显卡还是cpu,但是训练够慢的。
opencv_createsamples.exe -info pos\pos.txt -vec pos.vec -bg neg\neg.txt -num 2000 -w 20 -h 20
-info 输入正样本描述文件,默认NULL
-img 输入图像文件名,默认NULL
-bg 负样本描述文件,文件中包含一系列的被随机选作物体背景的图像文件名,默认NULL
-num 生成正样本的数目,默认1000
-bgcolor 背景颜色,表示透明颜色,默认0
-bgthresh 颜色容差,所有处于bgcolor-bgthresh和bgcolor+bgthresh之间的像素被置为透明像 素,也就是将白噪声加到前景图像上,默认80
-inv 前景图像颜色翻转标志,如果指定颜色翻转,默认0(不翻转)
-randinv 如果指定颜色将随机翻转,默认0
-maxidev 前景图像中像素的亮度梯度最大值,默认40
-maxxangle X轴最大旋转角度,以弧度为单位,默认1.1
-maxyangle Y轴最大旋转角度,以弧度为单位,默认1.1
-maxzangle Z轴最大旋转角度,以弧度为单位,默认0.5我们也看到了,许多命令都是默认的
opencv_traincascade.exe -data xml -vec pos.vec -bg neg\neg.txt -numPos 2000 -numNeg 5000 -numStages 20 -featureType HAAR -w 20 -h 20
-data 目录名xml,存放训练好的分类器,如果不存在训练程序自行创建
-vec pos.vec文件,由opencv_createsamples生成
-bg 负样本描述文件, neg\neg.txt
-numPos 每级分类器训练时所用到的正样本数目
-numNeg 每级分类器训练时所用到的负样本数目,可以大于-bg指定的图片数目
-numStages 训练分类器的级数,默认20级,一般在14-25层之间均可。 如果层数过多,分类器的fals alarm就更小,但是产生级联分类器的时间更长,分类器的hitrate就更小,检测速度就慢。如果正负样本较少,层数没必要设置很多。
-precalcValBufSize 缓存大小,用于存储预先计算的特征值,单位MB
-precalcIdxBufSize 缓存大小,用于存储预先计算的特征索引,单位M币
-baseFormatSave 仅在使用Haar特征时有效,如果指定,级联分类器将以老格式存储
-stageType 级联类型,staticconst char* stageTypes[] = { CC_BOOST };
-featureType 特征类型,staticconst char* featureTypes[] = { CC_HAAR, CC_LBP, CC_HOG };
-w
-h 训练样本的尺寸,必须跟使用opencv_createsamples创建的训练样本尺寸保持一致
-bt Boosted分类器类型 DAB-discrete Adaboost, RAB-RealAdaboost, LB-LogiBoost, GAB-Gentle Adaboost
-minHitRate 分类器的每一级希望得到的最小检测率,总的最大检测率大约为min_hit_rate^number_of_stages
-maxFalseAlarmRate 分类器的每一级希望得到的最大误检率,总的误检率大约为max_false_rate^number_of_stages
-weightTrimRate Specifies whether trimming should beused and its weight. 一个还不错的数值是0.95
-maxDepth 弱分类器的最大深度,一个不错数值是1,二叉树
-maxWeightCount 每一级中弱分类器的最大数目
更多内容请搜索:opencv_createsamples源码剖析
python代码-图像裁剪import cv2
import os
dir_path = os.path.dirname("G:\\face_regconition\\opencv_5\\self_trian_cascade\\neg\\")
neg_imgs = os.listdir("G:\\face_regconition\\opencv_5\\self_trian_cascade\\neg")
i = 0
for i in neg_imgs:
absolute_path = os.path.join(dir_path, i)
img = cv2.imread(absolute_path)
dst = cv2.resize(img, (60,60), 0, 0, cv2.INTER_LINEAR) #修改图片大小
a = cv2.imwrite(absolute_path, dst)
if a == True:
print(i)
i += 1
print("over")
可以修改路径和参数改变图像信息
python代码-图片转灰度图import cv2
import numpy as np
import os
neg_dir_path = os.path.dirname("G:\\face_regconition\\opencv_5\\self_trian_cascade\\neg\\")
neg_imgs = os.listdir("G:\\face_regconition\\opencv_5\\self_trian_cascade\\neg")
pos_dir_path = os.path.dirname("G:\\face_regconition\\opencv_5\\self_trian_cascade\\pos\\")
pos_imgs = os.listdir("G:\\face_regconition\\opencv_5\\self_trian_cascade\\pos")
def bgr2gray(imgs, dir_path):
i = 1
for img in imgs:
absolute_path = os.path.join(dir_path, img)
img_bgr = cv2.imread(absolute_path)
img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_RGB2GRAY)
judge = cv2.imwrite("G:\\face_regconition\\opencv_5\\self_trian_cascade\\new"+ "\\" + str(i) + ".jpg", img_gray)
if judge == 1:
i += 1
os.remove(absolute_path)
def bgr2gray_recurse(imgs, dir_path):
i = 0
for dirs in imgs:
new_dir = dir_path + "\\" +dirs
if os.path.isdir(new_dir):
imgs_name = os.listdir(dir_path + "\\" + dirs)
for img in imgs_name:
absolute_path = os.path.join(new_dir +"\\"+ img)
if "Thumbs.db" not in absolute_path:
img_bgr = cv2.imread(absolute_path)
img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_RGB2GRAY)
judge = cv2.imwrite(dir_path + "\\" + str(i) + ".jpg", img_gray)
if judge == 1:
i += 1
os.remove(absolute_path)
bgr2gray(neg_imgs, neg_dir_path)
bgr2gray_recurse(pos_imgs, pos_dir_path)
上面的代码也需要做稍许修改。上面的函数是对图片直接修改成灰度,下面是对树形目录修改的代码。
python代码-测试import cv2
# 实例化人脸分类器
face_cascade = cv2.CascadeClassifier('G:\\face_regconition\\haarshare\\haarcascade_frontalface_default.xml')
# 读取测试图片
img = cv2.imread('G:\\face_regconition\\opencv_5\\self_trian_cascade\\123.jpg', cv2.IMREAD_COLOR)
# 将原彩色图转换成灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 开始在灰度图上检测人脸,输出是人脸区域的外接矩形框
faces = face_cascade.detectMultiScale(gray, 1.2, 8)
# 遍历人脸检测结果
for (x, y, w, h) in faces:
# 在原彩色图上画人脸矩形框
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
# 获取该人脸矩形框的感兴趣区域RoI, 浅复制
roi_gray = gray[y:y + h, x:x + w]
roi_color = img[y:y + h, x:x + w]
# 显示画好矩形框的图片
cv2.namedWindow('faces', 0)
cv2.imshow('faces', img)
# 等待退出键
cv2.waitKey(0)
# 销毁显示窗口
cv2.destroyAllWindows()
由于写总结的时候这篇文章还没写完,所以用的.xml
文件是opencv自己训练好的。等训练好,用xml文件夹
下的非stages
文件即可。
还有类似修改文件名的代码:
os.rename(oldname, newname)
剩下的,就是数据了。数据我放在csdn的网站上,请依情况自行参考。开源,不要金币。
文件下载下来之后,把xml
文件夹里面的文件删掉,neg.txt
和pos.txt
中的内容按照自己的存放地址替换一下,删掉最后的一行不一样的文字。
参考:
https://blog.csdn.net/lql0716/article/details/72566839
https://blog.csdn.net/weixin_41799483/article/details/80567909