【GitHub开源项目实践】人脸口罩检测
  3TaxIqXGeDtF 2023年11月02日 23 0


昨天在GitHub上看到一个有趣的开源项目,它能检测我们是否有戴口罩,跑起程序测试后,发现识别率挺高的,也适应不同环境;于是分享给大家。

首先感谢​​AIZOOTech​​​ 的开源项目--​​FaceMaskDetection​​  😀

​人脸口罩检测工程--GitHub地址​

测试环境

windows 系统; 软件:pyCharm;    使用模型:tenforflow ;           

先看一下效果:

【GitHub开源项目实践】人脸口罩检测_ide

检测出帅气的胡歌没有带口罩。红色框框是圈出人脸部分,上方的字体:NoMask ,准确率 1 (即有100%把握认为没带口罩)

 

如果在多人的情况下,能检测出来吗?

【GitHub开源项目实践】人脸口罩检测_tensorflow_02

不错不错,这个模型能同时检测多人的,并且准确高。

 

有人带口罩,有人没带口罩,能检测出来吗?

【GitHub开源项目实践】人脸口罩检测_python_03

哇,这个模型很棒。检测出带口罩大叔,和两个没带口罩的小伙子。

 

大家先到网页体验一下呀

​https://aizoo.com/face-mask-detection.html​

【GitHub开源项目实践】人脸口罩检测_网盘_04

 

 

下面介绍一下此项目:

1)支持5大主流深度学习框架(PyTorch、TensorFlow、MXNet、Keras和Caffe),已经写好接口了;可以根据自身的环境选择合适的框架,比如:TensorFlow;所有模型都在​​models​​文件夹下。

2)公开了进8000张的人脸口罩数据和模型,数据集来自于​​WIDER Face​​​和​​MAFA​​数据集, 重新修改了标注并进行了校验(主要是 MAFA和WIDER Face的人脸位置定义不一样,所以进行了修改标注)并将其开源出来。

需要数据的朋友可以去拿,放到了网盘:​​https://pan.baidu.com/s/1eV07j2Vi8h3mn9X7xUKSgw​​    

提取码:45ku

 

模型结构

在本项目中使用了SSD类型的架构,为了让模型可以实时的跑在浏览器以及终端设备上,将模型设计的非常小,只有101.5万个参数。模型结构在本文附录部分。

本模型输入大小为260x260,主干网络只有8个卷积层,加上定位和分类层,一共只有24层(每层的通道数目基本都是32\64\128),所以模型特别小,只有101.5万参数。模型对于普通人脸基本都能检测出来,但是对于小人脸,检测效果肯定不如大模型。具体效果,大家可以点击以下链接,访问AIZOOTech的网站在线体验效果。 ​​aizoo.com跑在您浏览器的口罩检测模型​

网页使用了Tensorflow.js库,所以模型是完全运行在浏览器里面的。运行速度的快慢,取决于电脑配置的高低。

模型在五个卷积层上接出来了定位分类层,其大小和anchor设置信息如下表.

【GitHub开源项目实践】人脸口罩检测_python_05

 

工程包目录结构分析

GitHub工程包下载:​​https://github.com/AIZOOTech/FaceMaskDetection​

下载完​​FaceMaskDetection​​压缩包后,解压后如下图:

【GitHub开源项目实践】人脸口罩检测_ide_06

如果觉得工程包在GitHub下载太慢了,有时下载中断,可以到我网盘中拿:

链接:​​https://pan.baidu.com/s/1oMKSbTZFJOL0DX5GjTyKUA​​    提取码:vxnb

上图中的 tenforflow更正为 tensorflow,感谢指正。

 

如何运行程序

以 tensorflow 模型为例子,默认代码中tensorflow 版本应该是1.x;

如果是tensorflow版本是2.x的朋友,对应函数修改为tf.compat.v1.xxxx,使函数与1.x版本兼容。


最近接触到tensorflow2.x版本,相关的tensorflow版本导致函数不兼容的问题已经修改好了,需要tensorflow2.x 版本工程的朋友可以到网盘中拿: 链接:​​https://pan.baidu.com/s/10IQ1uscONZOYkgdtjcx2pQ​​    提取码:g8g9 

关于不知道如果搭建tensorflow2.x 的朋友请参考:​​【搭建神经网络开发环境--TensorFlow2框架】Windows系统+ Anaconda+ PyCharm+ Python​​

这里环境是tensorflow2.1;opencv4.2;

 

如果想运行图片:

python tensorflow_infer.py  --img-path /path/to/your/img

比如,img目录中作者放了一些图片的,选择demo2.jpg

python tensorflow_infer.py  --img-path  img/demo2.jpg

运行结果: 

【GitHub开源项目实践】人脸口罩检测_网盘_07

 

如果想运行运行视频

python tensorflow_infer.py --img-mode 0 --video-path /path/to/video

/path/to/video   为视频所在的路径+视频名

 

如果想实时使用摄像头检测

python tensorflow_infer.py --img-mode 0 --video-path 0

这里的0 ,代表在电脑中设备号;0默认为电脑自带的摄像头;

如果想使用外接摄像头,可以改为1 (比如:外接上一个USB摄像头)

 

这里看一下tensorflow_infer.py 代码:

# -*- coding:utf-8 -*-
import cv2
import time
import argparse

import numpy as np
from PIL import Image
from keras.models import model_from_json
from utils.anchor_generator import generate_anchors
from utils.anchor_decode import decode_bbox
from utils.nms import single_class_non_max_suppression
from load_model.tensorflow_loader import load_tf_model, tf_inference


#sess, graph = load_tf_model('FaceMaskDetection-master\models\face_mask_detection.pb')
sess, graph = load_tf_model('models\face_mask_detection.pb')
# anchor configuration
feature_map_sizes = [[33, 33], [17, 17], [9, 9], [5, 5], [3, 3]]
anchor_sizes = [[0.04, 0.056], [0.08, 0.11], [0.16, 0.22], [0.32, 0.45], [0.64, 0.72]]
anchor_ratios = [[1, 0.62, 0.42]] * 5

# generate anchors
anchors = generate_anchors(feature_map_sizes, anchor_sizes, anchor_ratios)

#用于推断,批大小为1,模型输出形状为[1,N,4],因此将锚点的dim扩展为[1,anchor_num,4]
anchors_exp = np.expand_dims(anchors, axis=0)
id2class = {0: 'Mask', 1: 'NoMask'}


def inference(image, conf_thresh=0.5, iou_thresh=0.4, target_shape=(160, 160), draw_result=True, show_result=True):
''' 检测推理的主要功能
# :param image:3D numpy图片数组
# :param conf_thresh:分类概率的最小阈值。
# :param iou_thresh:网管的IOU门限
# :param target_shape:模型输入大小。
# :param draw_result:是否将边框拖入图像。
# :param show_result:是否显示图像。
'''
# image = np.copy(image)
output_info = []
height, width, _ = image.shape
image_resized = cv2.resize(image, target_shape)
image_np = image_resized / 255.0 # 归一化到0~1
image_exp = np.expand_dims(image_np, axis=0)
y_bboxes_output, y_cls_output = tf_inference(sess, graph, image_exp)

# remove the batch dimension, for batch is always 1 for inference.
y_bboxes = decode_bbox(anchors_exp, y_bboxes_output)[0]
y_cls = y_cls_output[0]
# 为了加快速度,请执行单类NMS,而不是多类NMS。
bbox_max_scores = np.max(y_cls, axis=1)
bbox_max_score_classes = np.argmax(y_cls, axis=1)

# keep_idx是nms之后的活动边界框。
keep_idxs = single_class_non_max_suppression(y_bboxes, bbox_max_scores, conf_thresh=conf_thresh,iou_thresh=iou_thresh)
for idx in keep_idxs:
conf = float(bbox_max_scores[idx])
class_id = bbox_max_score_classes[idx]
bbox = y_bboxes[idx]
# 裁剪坐标,避免该值超出图像边界。
xmin = max(0, int(bbox[0] * width))
ymin = max(0, int(bbox[1] * height))
xmax = min(int(bbox[2] * width), width)
ymax = min(int(bbox[3] * height), height)

if draw_result:
if class_id == 0:
color = (0, 255, 0)
else:
color = (255, 0, 0)
cv2.rectangle(image, (xmin, ymin), (xmax, ymax), color, 2)
cv2.putText(image, "%s: %.2f" % (id2class[class_id], conf), (xmin + 2, ymin - 2),
cv2.FONT_HERSHEY_SIMPLEX, 1, color)
output_info.append([class_id, conf, xmin, ymin, xmax, ymax])

if show_result:
Image.fromarray(image).show()
return output_info


def run_on_video(video_path, output_video_name, conf_thresh):
cap = cv2.VideoCapture(video_path)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
fps = cap.get(cv2.CAP_PROP_FPS)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
#writer = cv2.VideoWriter(output_video_name, fourcc, int(fps), (int(width), int(height)))
total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
if not cap.isOpened():
raise ValueError("Video open failed.")
return
status = True
idx = 0
while status:
start_stamp = time.time()
status, img_raw = cap.read()
img_raw = cv2.cvtColor(img_raw, cv2.COLOR_BGR2RGB)
read_frame_stamp = time.time()
if (status):
inference(img_raw,
conf_thresh,
iou_thresh=0.5,
target_shape=(260, 260),
draw_result=True,
show_result=False)
cv2.imshow('image', img_raw[:, :, ::-1])
cv2.waitKey(1)
inference_stamp = time.time()
# writer.write(img_raw)
write_frame_stamp = time.time()
idx += 1
print("%d of %d" % (idx, total_frames))
print("read_frame:%f, infer time:%f, write time:%f" % (read_frame_stamp - start_stamp,
inference_stamp - read_frame_stamp,
write_frame_stamp - inference_stamp))
# writer.release()


if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Face Mask Detection")
parser.add_argument('--img-mode', type=int, default=0, help='set 1 to run on image, 0 to run on video.') #这里设置为1:检测图片;还是设置为0:视频文件(实时图像数据)检测
parser.add_argument('--img-path', type=str, help='path to your image.')
parser.add_argument('--video-path', type=str, default='0', help='path to your video, `0` means to use camera.')
# parser.add_argument('--hdf5', type=str, help='keras hdf5 file')
args = parser.parse_args()
if args.img_mode:
imgPath = args.img_path
#img = cv2.imread("imgPath")
img = cv2.imread(imgPath)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
inference(img, show_result=True, target_shape=(260, 260))
else:
video_path = args.video_path
if args.video_path == '0':
video_path = 0
run_on_video(video_path, '', conf_thresh=0.5)

测试集PR曲线

因为WIDER face是一个任务比较复杂的数据集,模型又设计的非常小,所以对于人脸的PR曲线并不是那么性感。这点可以通过设计大模型来提升对于小人脸的检测效果。

【GitHub开源项目实践】人脸口罩检测_ide_08

 

再次感谢AIZOOTech​ 的开源项目--FaceMaskDetection   

 

 


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  b1UHV4WKBb2S   2023年11月13日   25   0   0 ide抗锯齿
  b1UHV4WKBb2S   2023年11月13日   21   0   0 裁剪ideflutter
  zSWNgACtCQuP   2023年11月13日   20   0   0 ide
3TaxIqXGeDtF