基于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  文件!最后感谢所有负重前行的追梦人,加油!

后面发现摘下眼镜的识别准确度大大提高,吓到我了!原因就是 泛化能力太强了,因为正样本没有戴眼镜的图片,所有后期改进应当适当加入戴眼镜戴口罩的图片。然后负样本应该具有广泛性,不仅仅是人脸,还可以加上身体。然后提高训练数量。这个模型应该可以达到非常好的效果。

附上两张效果对比照片:

发布了44 篇原创文章 · 获赞 72 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/cj151525/article/details/104984897