欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python基于Opencv的是否戴口罩识别系统

程序员文章站 2022-07-13 10:10:09
...

疫情之下,有人选择负重前行,有人在年假与工作中毅然选择后者。感谢“疫”路有你,祝愿祖国繁荣昌盛,国泰民安!

人脸识别技术已经非常普及啦,现在戴口罩的脸支付宝也可以识别,据报道阿里现在正在尝试主导人脸识别技术的某些标准。在商业上大多数公司会选择国内AI大咖,比如百度智能云、阿里智慧云、华为云、腾讯云等等。这些平台的AI解决方案可以说代表了中国AI的最高水平。那么不使用他们提供的技术我们能不能做相关方面的开发呢?我的答案是可以!不吹不黑,其效果适用于精度要求不是很高的场景,满足一般需求。当然无法比拟这些巨头公司!

特殊时期在某些场合,比如药店、菜市场门口有无私的工作人员提醒戴口罩、测量体温。那么对于是否戴口罩能不能交给计算机去完成呢?我们只需要一台电脑一个摄像头就行,当然实际比这要复杂很多,需要考虑很多非技术上面的因素。今天我们只从这一技术层面使用开源社区的计算机视觉库OpenCv解决。

所以我的想法就是这样:

Python基于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不太准确,而且噪音样本影响非常大。我可能要将数据处理的干净才能保证准确性。想要照片的同学可以到这来下载

Python基于Opencv的是否戴口罩识别系统 Python基于Opencv的是否戴口罩识别系统

第一步:将所有照片的命名统计到Excel表格,这样便于循环遍历读取处理每一张照片。操作方法是:打开cmd,cd进所有照片的上级目录,然后敲下面的命令:

dir /b/s/p/w *.jpg > pos.txt

我所有照片放在文件夹1下面就这样操作:

Python基于Opencv的是否戴口罩识别系统

然后跑到1文件夹下面去,会发现这样一个txt文本,里面记录里该文件夹下所有文件名,复制到Excel里面就可以在Python中读取文件路径了。如下图:

Python基于Opencv的是否戴口罩识别系统

第二步:我们直接拿这些戴口罩的照片去训练是不行的,因为一整张照片脸和口罩的比例非常小。其他部位比如手、肩膀、等等动作都是噪音,我们并不需要拿去训练,它不但会增加CPU的计算量还会干扰模型。所有我们要进行裁减处理,裁减出戴口罩的人脸,因为OpenCv识别人脸时有些误差,我们需要手动删除不合格的口罩人脸灰度图。正样本:仅包含被检测物体的样本,并且距离边界尽量要小,图片尺寸大小一致。负样本:不包含被检测物体的样本,图片尺寸大小无要求。在裁减的时候顺便灰度处理。如下:

Python基于Opencv的是否戴口罩识别系统

下面是负样本,照片用于学习交流,不存在盈利目的,所以我认为不构成侵权行为,不过向我发律师函的话我立马删,真的!因为我怂!公民享有肖像权,未经本人同意,不得以营利为目的使用公民的肖像。”构成侵犯公民肖像权的行为,通常应具备两个要件:一是未经本人同意;二是以营利为目的。常见的侵犯公民肖像权的行为,主要是未经本人同意、以营利为目的使用他人肖像做商业广告、商品装潢、书刊封面及印刷挂历等。 好吧有点扯远了!

Python基于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)

Python基于Opencv的是否戴口罩识别系统

以下有些是参考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文件

Python基于Opencv的是否戴口罩识别系统

训练样本新建文件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

Python基于Opencv的是否戴口罩识别系统

复制进去保存,把pos.txt和neg.txt改回如图格式(注意:这一步至关中重要)并且还要新建xml文件夹!

Python基于Opencv的是否戴口罩识别系统

运行traincascade.bat等待就能得到xml文件:

如果出错了就参考这位博主的博客吧!

HR 是击中率(理解为模型猜对了的概率吧!),FA是 虚警率(也就是虚报率吗?理解为模型搞错了的概率吧)不是太懂,个人这样理解,反正击中率越高虚警率越低这个模型比较好,但也要考虑泛化嘛?懂的朋友赐教一下哈,只有当每一层训练的FA低于你的命令中声明的maxfalsealarm数值才会进入下一层训练。前面10层比较快,后面就非常慢了。但是心情非常开心,就像看着自己小心翼翼抚养的一个小宝贝马上要长大了的感觉,哈哈哈哈哈哈哈哈哈。小骄傲!

虚警率已经达标不再进行训练!下面使用训练出来的xml来进行戴口罩人脸识别!

Python基于Opencv的是否戴口罩识别系统

 

最后的效果还不错,没戴口罩根本识别不出,戴了口罩识别需要在光线明亮下才能很好识别,否则的话效果不是非常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  文件!最后感谢所有负重前行的追梦人,加油!