理论思路介绍篇,可以查看往日文章。
项目实现环境:
基于Python 3.8.1版本
opencv-python 4.2.0.34版本
需要自己下载OpenCV的库文件,添加其中的分类器
首先要引入相应的级联分类器
本项目一共使用了三个级联分类器:
人脸面部识别树:haarcascade_frontalface_alt2.xml
人脸面部鼻子识别树:haarcascade_mcs_nose.xml
口罩检测识别训练树:cascade.xml(这个训练的级联分类器是第三方制作文件,非OpenCV原厂训练文件)
import cv2.cv2 as cv
import time
import numpy as np
import pygame
import threading
以上的相应库函数,通过python的pip可以进行添加,添加OpenCV库的时候容易出现多个bug,建议参考以前的文章OpenCV的安装。
引入分类器时候,注意使用分类器是要将其引入的地址填写正确。
face_cascade = cv.CascadeClassifier('D:/OPENCV/opencv/build/etc/haarcascades/haarcascade_frontalface_alt2.xml')#人脸面部识别
eye_cascade = cv.CascadeClassifier('D:/OPENCV/opencv/build/etc/haarcascades/haarcascade_eye_tree_eyeglasses.xml')#面部眼镜识别
nose_cascade = cv.CascadeClassifier('D:/OPENCV/opencv/build/etc/haarcascades/haarcascade_mcs_nose.xml')#人脸面部鼻子识别
mask_detector = cv.CascadeClassifier("D:/OPENCV/opencv/build/etc/haarcascades/cascade.xml")#人脸佩戴口罩识别
1.img(必需)
这个不用多解释,显然是要输入的图像。图像可以是彩色也可以是灰度的。
2.foundLocations
存取检测到的目标位置
3.hitThreshold (可选)
opencv documents的解释是特征到SVM超平面的距离的阈值(Threshold for the distance between features and SVM classifying plane)
所以说这个参数可能是控制HOG特征与SVM最优超平面间的最大距离,当距离小于阈值时则判定为目标。
4.winStride(可选)
HoG检测窗口移动时的步长(水平及竖直)。
winStride和scale都是比较重要的参数,需要合理的设置。一个合适参数能够大大提升检测精确度,同时也不会使检测时间太长。
5.padding(可选)
在原图外围添加像素,作者在原文中提到,适当的pad可以提高检测的准确率(可能pad后能检测到边角的目标?)
常见的pad size 有(8, 8), (16, 16), (24, 24), (32, 32).
6.scale(可选)
图是一个图像金字塔,也就是图像的多尺度表示。每层图像都被缩小尺寸并用gaussian平滑。
scale参数可以具体控制金字塔的层数,参数越小,层数越多,检测时间也长。 一下分别是1.01 1.5 1.03 时检测到的目标。 通常scale在1.01-1.5这个区间
7.finalThreshold(可选)
这个参数不太清楚,有人说是为了优化最后的bounding box
8.useMeanShiftGrouping(可选)
bool 类型,决定是否应用meanshift 来消除重叠。
default为false,通常也设为false,另行应用non-maxima supperssion效果更好。
实际代码
ret, frame = cameraCapture.read()#首先是将摄像头转化的输出转化为一帧一帧的图像
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)将图像转化为灰度图像,减少运算量
faces = face_cascade.detectMultiScale(gray, 1.2, 10)#运用比对函数1.2为每次以1.2倍移动比对,10为识别次数为10次便认为是我们需要的图像。
masks = mask_detector.detectMultiScale(gray, 1.03, 5)#
noses = nose_cascade.detectMultiScale(gray, 1.2, 10)#
对比参数需要按照实际情况进行测试和调整,有时候将对比次数调整的过高将会导致程序的运算量过大,虽然准确无误,但是又会忽略许多的残缺实际对象,比如上图中的小孩子,就会被忽略。
代码如下(示例):
ret, frame = cameraCapture.read()
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.2, 10)# 1.02
masks = mask_detector.detectMultiScale(gray, 1.03, 5)# 1.01
noses = nose_cascade.detectMultiScale(gray, 1.2, 10)# 1.05
for (x, y, w, h) in faces:
cv.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
cv.putText(frame, "no_mask", (x, y), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
n = n + 1
no_mask = no_mask+1
for (mx, my, mw, mh) in masks:
cv.rectangle(frame, (mx, my), (mx + mw, my + mh), (0, 255, 0), 2)
cv.putText(frame, "have_mask", (mx, my), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
n = n + 1
have_mask = have_mask + 1
for (nx, ny, nw, nh) in noses:
cv.rectangle(frame, (nx, ny), (nx + nw, ny + nh), (10, 10, 255), 2)
cv.putText(frame, "no_mask", (nx, ny), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
# n = 1
no_mask = 1
通过识别和比对,输出的值将通过for循环输出,并且使用OpenCV画出矩形框,并得出是否佩戴口罩。
以下为测试结果:
在图像中通过分类器比对,找到了匹配的数据后,将所得到的数据进行画框,并且输出出来了。以上为全脸未带口罩,识别出了鼻子和人脸,使用红色框图进行表示。
以上为佩戴口罩状态,将会识别佩戴口罩的人脸,并且用绿色框图表示。
在佩戴口罩不完全时,主要以识别口鼻等关键部位,进行判断是否佩戴了口罩。
在对比效率的情况下,测试结果为,未佩戴眼镜时,匹配准确率和效率都较为高。主要原因分析:由于引入的级联分类器的训练样本多为未佩戴眼镜的,所以在配戴眼镜时,会对其产生一定的干扰。
项目一:只含有口罩识别,未添加语音提醒。
import cv2.cv2 as cv
import time
import pygame
def detect():
n = 0
have_mask = 0
no_mask = 0
face_cascade = cv.CascadeClassifier('D:/OPENCV/opencv/build/etc/haarcascades/haarcascade_frontalface_alt2.xml')
eye_cascade = cv.CascadeClassifier('D:/OPENCV/opencv/build/etc/haarcascades/haarcascade_eye_tree_eyeglasses.xml')
nose_cascade = cv.CascadeClassifier('D:/OPENCV/opencv/build/etc/haarcascades/haarcascade_mcs_nose.xml')
mask_detector = cv.CascadeClassifier("D:/OPENCV/opencv/build/etc/haarcascades/cascade.xml")
cameraCapture = cv.VideoCapture(0, cv.CAP_DSHOW)# cv.CAP_DSHOW
while True:
start = time.time()
ret, frame = cameraCapture.read()
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.2, 10)# 1.02
masks = mask_detector.detectMultiScale(gray, 1.03, 5)# 1.01
noses = nose_cascade.detectMultiScale(gray, 1.2, 10)# 1.05
for (x, y, w, h) in faces:
cv.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
cv.putText(frame, "no_mask", (x, y), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
n = 1
have_mask = 1
# roi_gray = gray[y:y+h, x:x+w]
# img = frame[y:y+h, x:x+w]
# eyes = eye_cascade.detectMultiScale(roi_gray, 1.03, 8, 0)
# for (ex, ey, ew, eh) in eyes:
# cv.rectangle(img, (ex, ey), (ex+ew, ey+eh), (0, 255, 255), 2)
for (mx, my, mw, mh) in masks:
cv.rectangle(frame, (mx, my), (mx + mw, my + mh), (0, 255, 0), 2)
cv.putText(frame, "have_mask", (mx, my), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
n = 1
no_mask = 1
for (nx, ny, nw, nh) in noses:
cv.rectangle(frame, (nx, ny), (nx + nw, ny + nh), (10, 10, 255), 2)
cv.putText(frame, "no_mask", (nx, ny), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
n = 1
no_mask = 1
c = cv.waitKey(50)
if c == 27:
break
# 计算帧率
end = time.time() # 结束时间
fps = 1 / (end - start) # 帧率
image = cv.putText(frame, "fps:{:.3f}".format(fps), (550, 15), cv.FONT_HERSHEY_COMPLEX, 0.5, (0, 255, 0), 1) # 绘制
image2 = cv.putText(image, f"Number of people tested:{n}", (400, 40), cv.FONT_HERSHEY_COMPLEX, 0.5, (0, 255, 255), 1)
image3 = cv.putText(image2, f'Number of people wearing masks:{have_mask}', (325, 60), cv.FONT_HERSHEY_COMPLEX, 0.5, (0, 255, 0), 1)
image4 = cv.putText(image3, f'Number of people not wearing masks:{no_mask}', (290, 80), cv.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 255), 1)
cv.imshow('camera', image4)
cameraCapture.release()
cv.destroyAllWindows()
if __name__=='__main__':
detect()
文章书写不易,如果对你有帮助的话,可以给作者点个赞嘛!
你的点赞,评论,收藏,是对我们最大的支持和帮助!