Python基于Opencv的是否戴口罩识别系统
疫情之下,有人选择负重前行,有人在年假与工作中毅然选择后者。感谢“疫”路有你,祝愿祖国繁荣昌盛,国泰民安!
人脸识别技术已经非常普及啦,现在戴口罩的脸支付宝也可以识别,据报道阿里现在正在尝试主导人脸识别技术的某些标准。在商业上大多数公司会选择国内AI大咖,比如百度智能云、阿里智慧云、华为云、腾讯云等等。这些平台的AI解决方案可以说代表了中国AI的最高水平。那么不使用他们提供的技术我们能不能做相关方面的开发呢?我的答案是可以!不吹不黑,其效果适用于精度要求不是很高的场景,满足一般需求。当然无法比拟这些巨头公司!
特殊时期在某些场合,比如药店、菜市场门口有无私的工作人员提醒戴口罩、测量体温。那么对于是否戴口罩能不能交给计算机去完成呢?我们只需要一台电脑一个摄像头就行,当然实际比这要复杂很多,需要考虑很多非技术上面的因素。今天我们只从这一技术层面使用开源社区的计算机视觉库OpenCv解决。
所以我的想法就是这样:
下面就按照以上的步骤去实现,分为以下几个阶段:
环境的搭建:
所需环境:OpenCv-Python,Python3.0版本
安装Opencv参考 零一样的存在 的博客
开启摄像头并检测出人脸:
OpenCv在Python中的导入是cv2,直接调用即可完成前面三个步骤:原理其实很简单,如果你运行了下面的代码就能够发现,其实只是一个循环不断读摄像头的每一帧,然后灰度处理,再进行人脸检测。一张图片它之所以能够识别人脸,是因为有这样一个文件haarcascade_frontalface_default.xml 这个模型描述文件非常重要,这是OpenCv自带的人脸识别模型文件,当然还有自带其他的xml文件,比如笑脸识别,猫脸识别,眼睛识别等等,需要这个文件的话可以到 haarcascades下载一下,然后把它复制到项目就好。不过非常遗憾没有口罩人脸识别,不然就非常简单了。因此我们就需要自己去训练构造出一个这样的人脸口罩xml模型。
import cv2
#识别人脸的xml文件,构建人脸检测器
detector= cv2.CascadeClassifier('haarcascades\\haarcascade_frontalface_default.xml')
#获取0号摄像头的实例
cap = cv2.VideoCapture(0)
while True:
# 就是从摄像头获取到图像,这个函数返回了两个变量,第一个为布尔值表示成功与否,以及第二个是图像。
ret, img = cap.read()
转为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#获取人脸坐标
faces = detector.detectMultiScale(gray, 1.1, 3)
for (x, y, w, h) in faces:
#参数分别为 图片、左上角坐标,右下角坐标,颜色,厚度
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
cv2.imshow('Cheney', img)
cv2.waitKey(3)
cap.release()
cv2.destroyAllWindows()
训练分类器:
说明白一点,OpenCv是开源的,大家都可以使用,无需缴费。那就意味着它的精度不够高,鲁棒性差等缺点。不然就不会有那么多公司自主研发自己的人脸识别技术了。作为学生阶段使用OpenCv非常足够了,要知道OpenCv是一本非常厚的书,看完得费很大力气噢。我们目前研究的只是他的运用而非原理,如要深究原理的话,那就难受多了,这也许就把学硕与专硕区分开来了,这样理解如有偏差请批正!
数据预处理:
首先我们得去获取带了口罩的图片以及未戴口罩的人脸图片,我们把戴了口罩的照片看作正样本,未戴口罩的图片看作负样本。不妨先看下我收集到样本吧!左边是戴了口罩的图片,右边是未戴口罩的图片。我发现了一个现象,收集到的戴口罩图片基本上是女性的,可能与喜欢自拍有相关性,没研究哈哈。本来想直接用下面图片进行训练,可是一想到OpenCv不太准确,而且噪音样本影响非常大。我可能要将数据处理的干净才能保证准确性。想要照片的同学可以到这来下载!
第一步:将所有照片的命名统计到Excel表格,这样便于循环遍历读取处理每一张照片。操作方法是:打开cmd,cd进所有照片的上级目录,然后敲下面的命令:
dir /b/s/p/w *.jpg > pos.txt
我所有照片放在文件夹1下面就这样操作:
然后跑到1文件夹下面去,会发现这样一个txt文本,里面记录里该文件夹下所有文件名,复制到Excel里面就可以在Python中读取文件路径了。如下图:
第二步:我们直接拿这些戴口罩的照片去训练是不行的,因为一整张照片脸和口罩的比例非常小。其他部位比如手、肩膀、等等动作都是噪音,我们并不需要拿去训练,它不但会增加CPU的计算量还会干扰模型。所有我们要进行裁减处理,裁减出戴口罩的人脸,因为OpenCv识别人脸时有些误差,我们需要手动删除不合格的口罩人脸灰度图。正样本:仅包含被检测物体的样本,并且距离边界尽量要小,图片尺寸大小一致。负样本:不包含被检测物体的样本,图片尺寸大小无要求。在裁减的时候顺便灰度处理。如下:
下面是负样本,照片用于学习交流,不存在盈利目的,所以我认为不构成侵权行为,不过向我发律师函的话我立马删,真的!因为我怂!公民享有肖像权,未经本人同意,不得以营利为目的使用公民的肖像。”构成侵犯公民肖像权的行为,通常应具备两个要件:一是未经本人同意;二是以营利为目的。常见的侵犯公民肖像权的行为,主要是未经本人同意、以营利为目的使用他人肖像做商业广告、商品装潢、书刊封面及印刷挂历等。 好吧有点扯远了!
import pandas as pd
import cv2
names=pd.read_excel('data\\imgName.xlsx')['names']# 读取所有照片名字
i=100000 #用于重新命名
for imagepath in names:
#读取图片
img = cv2.imread(imagepath)
#转成灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#人脸识别器
detector = cv2.CascadeClassifier('haarcascades\\haarcascade_frontalface_default.xml')
#获取人脸位置
faces = detector.detectMultiScale(gray, 1.1, 5)
for (x, y, w, h) in faces:
#裁减图片
gray = gray[y:y+h,x:x+w] # 裁剪坐标为[y0:y1, x0:x1]
#如果人脸不为空
try:
# 保存裁减后的灰度图
cv2.imwrite('Q:\\GraduationProject\\mask\\gray1\\'+str(i)+'.jpg', gray)
# cv2.waitKey(3000)
i += 1
except:
print()
第三步:使得正样本的所有照片的像素一致(必须一致)这里使用50X50的像素,负样本的像素一定要大于50X50.
import pandas as pd
import cv2
for n in range(100000,100352):
path='Q:\\GraduationProject\\mask\\gray1_2\\'+str(n)+'.jpg'
# 读取图片
img = cv2.imread(path)
img=cv2.resize(img,(50,50))
cv2.imwrite('Q:\\GraduationProject\\mask\\gray1_2\\' + str(n) + '.jpg', img)
n += 1
并且在后面添加 1 0 0 50 50 (使用全部替换)pos.txt文件如下图所示:这里1表示当前图片重复出现的次数是1, 0 0 50 50表示目标图片大小是矩形框从(0,0)到(50,50)。 负样本只需要前面一列路径,后面不需要!(纠正一下,后来我调成了20X20的,因为官方推荐20X20)
以下有些是参考https://blog.csdn.net/qq_32502511/article/details/79010509这篇文章,告知侵删!
第四步:获取供训练的vec文件。先介绍一下我们的主角 opencv_createsamples.exe ,它位于OpenCV\build\x64\vc14\bin下面,它是用于创建样本描述文件,后缀名是.vec。专门为OpenCV训练准备,只有正样本需要,负样本不需要。opencv_traincascade.exe:是OpenCV自带的一个工具,封装了haar特征提取LBP和HOG特征分类器 。老版本有opencv_traincascade.exe,今天我们不用它。
一般来说,正负样本数目比例为1:3时训练结果较好,但是不是绝对。由于每个样本的差异性不同等因素,所以没有绝对的比例关系。但是负样本需要比正样本多,因为原则上说负样本的多样性越大越好,我们才能有效降低误检率,而不仅仅是通过正样本的训练让其能识别物体。在本次训练中,我选择了350个正样本和1100个负样本,均为灰度图像。
创建正样本vec文件
opencv_traincascade训练的时候需要输入的正样本是vec文件,所以需要使用createsamples程序来将正样本转换为vec文件。完成以上工作就前往主角 opencv_createsamples.exe 目录下OpenCV\build\x64\vc14\bin,复制pos.txt 和 neg.txt到该目录下:然后cmd进入该目录
opencv_createsamples.exe -vec pos.vec -info pos.txt -num 353 -w 20 -h 20
说明:
-info,指样本说明文件
-vec,样本描述文件的名字及路径
-num,总共几个样本,要注意,这里的样本数是指标定后的20x20的样本数,而不是大图的数目,其实就是样本说明文件第2列的所有数字累加
-w -h指明想让样本缩放到什么尺寸。
如图:得到pos.vec文件
训练样本新建文件traincascade.bat
把
opencv_traincascade.exe -data xml -vec pos.vec -bg neg.txt -numPos 500 -numNeg 656 -numStages 20 -w 20 -h 20 -mode ALL
pause
复制进去保存,把pos.txt和neg.txt改回如图格式(注意:这一步至关中重要)并且还要新建xml文件夹!
运行traincascade.bat等待就能得到xml文件:
如果出错了就参考这位博主的博客吧!
HR 是击中率(理解为模型猜对了的概率吧!),FA是 虚警率(也就是虚报率吗?理解为模型搞错了的概率吧)不是太懂,个人这样理解,反正击中率越高虚警率越低这个模型比较好,但也要考虑泛化嘛?懂的朋友赐教一下哈,只有当每一层训练的FA低于你的命令中声明的maxfalsealarm数值才会进入下一层训练。前面10层比较快,后面就非常慢了。但是心情非常开心,就像看着自己小心翼翼抚养的一个小宝贝马上要长大了的感觉,哈哈哈哈哈哈哈哈哈。小骄傲!
虚警率已经达标不再进行训练!下面使用训练出来的xml来进行戴口罩人脸识别!
最后的效果还不错,没戴口罩根本识别不出,戴了口罩识别需要在光线明亮下才能很好识别,否则的话效果不是非常nice。毕竟只用了330张正样本,找个时间跑一下1000样本,300正样本跑了将近两个小时,期间还中断了几下。总的来说效果达到了预期,以后尝试训练一千以上的正样本。
import cv2
detector= cv2.CascadeClassifier('haarcascades\\haarcascade_frontalface_default.xml')
mask_detector=cv2.CascadeClassifier('data\\cascade.xml')
cap = cv2.VideoCapture(0)
while True:
ret, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = detector.detectMultiScale(gray, 1.1, 3)
for (x, y, w, h) in faces:
#参数分别为 图片、左上角坐标,右下角坐标,颜色,厚度
face=img[y:y+h,x:x+w] # 裁剪坐标为[y0:y1, x0:x1]
mask_face=mask_detector.detectMultiScale(gray, 1.1, 5)
for (x2,y2,w2,h2) in mask_face:
cv2.rectangle(img, (x2, y2), (x2 + w2, y2 + h2), (0, 0, 255), 2)
cv2.imshow('Cheney', img)
cv2.waitKey(3)
cap.release()
cv2.destroyAllWindows()
附上跑出来的 cascade.xml 文件!最后感谢所有负重前行的追梦人,加油!
上一篇: MyBatis-Plus - 实现字段自动填充功能
下一篇: Direct3D融合技术