口罩检测识别率惊人,这个Python项目开源了
作者 | 一颗小树x,CSDN 博主
编辑 | 唐小引
来源 | CSDN 博客
昨天在 GitHub 上看到一个有趣的开源项目,它能检测我们是否有戴口罩,跑起程序测试后,发现识别率挺高的,也适应不同环境,于是分享给大家。
首先感谢 AIZOOTech 的开源项目 —— FaceMaskDetection????,以下为该项目的 GitHub 地址:
https://github.com/AIZOOTech/FaceMaskDetection
测试环境
我们采用:
Windows 系统;
软件:PyCharm;
使用模型:TensorFlow。
先看一下效果:
检测出帅气的胡歌没有带口罩。红色框框是圈出人脸部分,上方的字体:NoMask ,准确率 1 (即有 100% 把握认为没带口罩)。
如果在多人的情况下,能检测出来吗?如下图所示。
不错不错,这个模型能同时检测多人的,并且准确高。
有人带口罩,有人没带口罩,能检测出来吗?
哇,这个模型很棒。检测出带口罩大叔,和两个没带口罩的小伙子。
大家可以先在网页体验一下:
https://aizoo.com/face-mask-detection.html
接下来,我们具体分析一下这个项目:
支持 5 大主流深度学习框架(PyTorch、TensorFlow、MXNet、Keras 和 Caffe),已经写好接口了;可以根据自身的环境选择合适的框架,比如:TensorFlow;所有模型都在 models 文件夹下。
公开了近 8000 张的人脸口罩数据和模型,数据集来自于 WIDER Face 和 MAFA 数据集, 重新修改了标注并进行了校验(主要是 MAFA 和 WIDER Face 的人脸位置定义不一样,所以进行了修改标注)并将其开源出来。
模型结构
在本项目中使用了 SSD 类型的架构,为了让模型可以实时的跑在浏览器以及终端设备上,将模型设计的非常小,只有 101.5 万个参数。模型结构在本文附录部分。
本模型输入大小为 260x260,主干网络只有 8 个卷积层,加上定位和分类层,一共只有 24 层(每层的通道数目基本都是 32\64\128),所以模型特别小,只有 101.5 万参数。模型对于普通人脸基本都能检测出来,但是对于小人脸,检测效果肯定不如大模型。
网页使用了 Tensorflow.js 库,所以模型是完全运行在浏览器里面的。运行速度的快慢,取决于电脑配置的高低。
模型在五个卷积层上接出来了定位分类层,其大小和 anchor 设置信息如下表。
工程包目录结构分析
GitHub 工程包下载:
https://github.com/AIZOOTech/FaceMaskDetection
下载完 FaceMaskDetection 压缩包后,解压后如下图:
如何运行程序?
以 TensorFlow 模型为例子,代码中 TensorFlow 版本应该是 1.x;
如果是 TensorFlow 版本是 2.x 的朋友,对应函数修改为 tf.compat.v1.xxxx,使函数与 1.x 版本兼容。
如果想运行图片:
python tenforflow_infer.py --img-path /path/to/your/img
比如,img 目录中作者放了一些图片的,选择 demo2.jpg。
python tenforflow_infer.py --img-path img/demo2.jpg
运行结果:
如果想运行运行视频:
python tenforflow_infer.py --img-mode 0 --video-path /path/to/video
/path/to/video 为视频所在的路径+视频名。
如果想实时使用摄像头检测:
python tenforflow_infer.py --img-mode 0 --video-path 0
这里的 0 ,代表在电脑中设备号;0 默认为电脑自带的摄像头。
如果想使用外接摄像头,可以改为 1 (比如外接上一个 USB 摄像头)。
这里看一下 tenforflow_infer.py 代码:
# -*- coding:utf-8 -*-
import cv2
import time
import argparseimport 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.shapeimage_resized = cv2.resize(image, target_shape)image_np = image_resized / 255.0 # 归一化到0~1image_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_infodef 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.")returnstatus = Trueidx = 0while 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 += 1print("%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_pathif args.video_path == '0':video_path = 0run_on_video(video_path, '', conf_thresh=0.5)
测试集 PR 曲线
因为 WIDER face 是一个任务比较复杂的数据集,模型又设计的非常小,所以对于人脸的 PR 曲线并不是那么性感。这点可以通过设计大模型来提升对于小人脸的检测效果。
再次感谢 AIZOOTech 的开源项目 —— FaceMaskDetection。
【end】
◆
原力计划
◆
《原力计划【第二季】- 学习力挑战》正式开始!即日起至 3月21日,千万流量支持原创作者!更有专属【勋章】等你来挑战
推荐阅读
2019年度CSDN博客之星TOP10榜单揭晓,你上榜了吗?
Javascript函数之深入浅出递归思想,附案例与代码!
不看就亏系列!这里有完整的 Hadoop 集群搭建教程,和最易懂的 Hadoop 概念!| 附代码
智能合约编写之Solidity的基础特性
微信七年「封链」史
计算机博士、加班到凌晨也要化妆、段子手……IT 女神驾到!
你点的每个“在看”,我都认真当成了AI
相关文章:

CentOS搭建msmtp+mutt实现邮件发送
1:搭建配置msmtp下载msmtp包:官方地址:http://msmtp.sourceforge.net/download.html编译,安装(官方下载的包为tar.xz格式):#xz -d msmtp-1.6.3.tar.xz #tar -xvf msmtp-1.6.3.tar #cd msmtp-1.6.3 #./configure --prefix /opt/app…
Linux环境下的堆栈--调试C程序
完整的调试过程,跟踪堆栈变化,32位下。 注意64位和此不同。 a.c代码: #include <stdio.h> int main() { AFunc(5,6);return 0; } int BFunc(int i,int j) {int m 1;int n 2;m i;n j; return m; }int AFunc(int i,int j) {…
听说过代码洁癖,Bug洁癖怎么解?
来源 | Python编程时光(ID: Cool-Python)当我们写的一个脚本或程序发生各种不可预知的异常时,如果我们没有进行捕获处理的时候,通常都会致使程序崩溃退出,并且会在终端打印出一堆 密密麻麻 的 traceback 堆栈信息来告诉…

POJO、VO、PO、FormBean区别:
首先讲一下四者的概念 POJO:Pure Old Java Object,符合Java Bean属性规范的简单Java对象,通常也称为VO(Value Object,值对象)。 VO:就是POJO; PO: Persistent Object,持久化对…

oracle中的sql%rowcount,sql%found、sql%notfound、sql%rowcount和sql%isopen
Oracle 存储过程 删除表记录时删除不存在的记录也是显示删除成功 create or replace procedure delDept(p_deptno in dept.deptno%type) is begindelete from dept where deptnop_deptno;dbms_output.put_line(部门删除成功...);exception when others thendbms_output.put_lin…

linux平台的链接与加载
原文是上下两篇 链接与加载(上) — 静态链接链接与加载(下) — 动态链接 为观看方便,现在合并起来。 一.静态链接 示例程序 我们先看一个简单的示例程序,代码如下: /*main.c*/int u 333;int sum(int, int);int main(int argc, char* argv…
预训练模型ProphetNet:根据未来文本信息进行自然语言生成
作者 | 刘大一恒、齐炜祯、晏宇、宫叶云、段楠、周明来源 | 微软研究院AI头条(ID:MSRAsia)编者按:微软亚洲研究院提出新的预训练模型 ProphetNet,提出了一种新的自监督学习目标——同时预测多个未来字符,在序列到序列的…

模拟进程管理小结,编码规范的重要性
废话不多说了,省的又有衰人找我麻烦。希望我讨厌的,和讨厌我的少来骚扰我,由衷的感谢它们。 我不回那些骚扰,是因为我见到名字就直接删了,看都懒的看了。也别怪我粗鲁,因为我一向是对什么人说什么话 的&…

JSPServlet路径问题
2019独角兽企业重金招聘Python工程师标准>>> 如果带WebRoot,那么js、css、img都应该放到WebRoot目录下,否则访问会有问题。千万不要放在WEB-INF下,因为WEB-INF下的内容只有服务器转发可以访问到,出于安全考虑。 如果不…

Git学习教程(六)Git日志
第六课 Git 日志 内容提要:浏览项目历史,查询指定提交内容,图形化显示分枝和合并...git log是git中最常用的一个命令,执行之后,会显示该项目的提交历史。如果命令不加任何参数,那么就会显示目前所在分枝上&…

汇编包含C代码
反汇编的时候带上C代码便于观察 比较三元表达式和if else的差异 a1.c #include <stdio.h> int main(void) { int a1;int b2;int c0;a (b>c)?1:0;return 0;} a2.c #include <stdio.h> int main(void) { int a1;int b2;int c0;if(b>c){a1;}else{a0;…
无需3D运动数据训练,最新人体姿势估计方法达到SOTA | CVPR 2020
作者 | Muhammed Kocabas译者 | 刘畅出品 | AI科技大本营(ID:rgznai100)人体的运动对于理解人的行为是非常重要的。尽管目前已经在单图像3D姿势和动作估计方面取得了进展,但由于缺少用于训练的真实的3D运动数据,因此现有的基于视频…

Linux内核跟踪之trace框架分析【转】
转自:http://blog.chinaunix.net/uid-20543183-id-1930846.html------------------------------------------本文系本站原创,欢迎转载!转载请注明出处:http://ericxiao.cublog.cn/------------------------------------------一: 前言本文主要是对trace的框架做详尽…
写给Python开发者:机器学习十大必备技能
作者 | Pratik Bhavsar译者 | 明明如月,编辑 | 夕颜来源 | CSDN(ID:CSDNnews)有时候,作为一个数据科学家,我们常常忘记了初心。我们首先是一个开发者,然后才是研究人员,最后才可能是数学家。我…

Linux环境程序栈溢出原理
当在缓冲区中输入过多的数据时,缓冲区溢出就会发生,C语言提供了多种方法,可以使在缓冲区中输入的数据比预期的多。 局部变量可以被分配到栈上。这就意味着在栈的某个地方有一个固定大小的缓冲区。 而栈是向下增长的,而且一些重要…

[翻译]Joomla 1.5架构(十一) model 包
这个包包含了跟数据表交互的所有相关类 JModel This abstract class is the base class for all Joomla! data access objects. 所有数据访问类的抽象基类。 以下的类都分别实现对不同表的访问,不再翻译了。 Adapter Folder JModelCategory This is a data access …

度量快速开发平台端口映射的介绍
度量快速开发平台在客户中部署的时候,可能会想内网与外网用户同时使用。一般情况下,服务端都是部署在内网的,那外网用户要访问,就可能用到端口映射的功能。端口映射基本都是在路由器上进行。下面就是几个常用的路由器上的设置方法…

为什么栈和堆的生长方向不一样
栈的生长方向 8051的栈是向高地址增长,INTEL的8031、8032、8048、8051系列使用向高地址增长的堆栈;但同样是INTEL,在x86系列中全部使用向低地址增长的堆栈。其他公司的CPU中除ARM的结构提供向高地址增长的堆栈选项外,多数都是使用…
简单粗暴理解与实现机器学习之逻辑回归:逻辑回归介绍、应用场景、原理、损失以及优化...
作者 | 汪雯琦责编 | Carol来源 | CSDN 博客出品 | AI科技大本营(ID:rgznai100)学习目标知道逻辑回归的损失函数知道逻辑回归的优化方法知道sigmoid函数知道逻辑回归的应用场景应用LogisticRegression实现逻辑回归预测知道精确率、召回率指标的区别知道如…

生命的脆弱——悼念朋友
生命的脆弱让我们敲希望的钟啊多少祈祷在心中让大家看不到失败叫成功永远在让地球忘记了转动啊四季少了夏秋冬让宇宙关不了天窗叫太阳不西沉让欢喜代替了哀愁啊微笑不会再害羞让时光懂得去倒流叫青春不开溜让贫穷开始去逃亡啊快乐健康留四方让世界找不到黑暗幸福像花开放让大家…

VMware Tools手动下载
2019独角兽企业重金招聘Python工程师标准>>> VMware自己下载VMware Tools非常慢。你可以自己手动下载它。 下载地址为: version: 8.8.2 http://softwareupdate.vmware.com/cds/vmw-desktop/ws/8.0.3/ 选择最新的build,例如: http:…

Linux查看多核CPU利用率
1.top 使用权限:所有使用者 使用方式:top [-] [d delay] [q] [c] [S] [s] [i] [n] [b] 说明:即时显示process的动态 d :改变显示的更新速度,或是在交谈式指令列( interactive command)按s q :没有任何延迟的显示速度…

仓央嘉措《那一天,那一月,那一年,那一世》
那一天, 我闭目在经殿的香雾中, 蓦然听见你颂经中的真言; 那一月, 我摇动所有的经筒, 不为超度, 只为触摸你的指尖; 那一年, 磕长头匍匐在…
AI+大数据助力抗疫,带你认识百度地图的新玩法!
作者 | Aholiab责编 | Carol出品 | AI科技大本营(ID:rgznai100)“喂,你好,我是百度地图的客服,请问是xx店铺对吗?”“嗯,什么事?”“您家在疫情期间还照常营业,对吗&…

Coursera Machine Learning 作业提交问题
关于作业提交问题的解决办法 Octave 4.0.0无法正常提交 解决办法:打两个补丁 补丁1:平台通用补丁2:Win,Linux or Mac 注:补丁文件中有安装说明

Linux查看进程内存状况
查看全部进程 通过top或ps -ef | grep 进程名 得到进程的PID。该命令可以提供进程状态、文件句柄数、内存使用情况等信息。 #pa aux 先查看进程 nginx的工作进程是5757 pmap命令 可以显示一个或多个进程所使用的内存数量。你可以使用这个工具来了解服务器上的某个进程分配…
用于小型图形挖掘研究的瑞士军刀:空手道俱乐部的图表学习Python库
作者 | Benedek Rozemberczki译者 | 天道酬勤 责编 | Carol出品 | AI科技大本营(ID:rgznai100)空手道俱乐部(Karate Club)是NetworkX Python软件包的无监督机器学习扩展库。详细可以参阅此处的文档:https://github.com…

电子商务创造的第二次产业机会
即将迎来冬至节气的这个周末,天寒地冻,却是电子商务的饕餮之季。淘宝网商交易大会刚刚在成都落下帷幕,而比网货交易会更令业界期待的“2009中国电子商务创新发展高峰论坛”也在北京顺利召开。大会由国内最大的电子商务软件及服务提供商ShopEx…

C#趣味程序---个位数为6,且能被3整出的五位数
using System;namespace ConsoleApplication1 {class Program{static void Main(string[] args){int count 0;int k;for (int i 1000; i < 9999; i){k i * 10 6;if (k % 3 0){Console.WriteLine(k);count;}}Console.WriteLine(count); }} }

c# winform 用子窗体刷新父窗体,子窗体改变父窗体控件的值
第一种方法: 用委托,Form2和Form3是同一组 Form2 usingSystem; usingSystem.Collections.Generic; usingSystem.ComponentModel; usingSystem.Data; usingSystem.Drawing; usingSystem.Text; usingSystem.Windows.Forms; namespaceTestMouseMove { pub…