百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

照片解锁手机不能忍?教你用OpenCV做活体检测 | 有代码

toyiye 2024-07-06 00:17 19 浏览 0 评论

圆栗子 编译整理

量子位 出品 | 公众号 QbitAI



来自虾米妈咪

小朋友用妈妈的一寸照片通过了人脸识别,打击了小度音箱的家长监督机制。

活体检测没做好。

公交车身广告上的董明珠头像,被宁波交警系统拍了照,判定成“违法闯红灯”。

活体检测没做好。

所以,活体检测要怎么做?

名叫Adrian Rosebrock的程序猿,写了份事无巨细的教程,从构建数据集开始,一步步教大家用AI分辨真人和照片,精细到每行代码的用途。



川川是假的,光头是真的

这个识别方法,用到了OpenCVKeras,打开摄像头就可以实时检测

重要的是,有源码提供,受到了推特用户的踊跃比心。

活体检测,可以检测些什么?

AI可以用哪些技巧,来区分真人和照片?

一是纹理分析 (Texture Analysis) 。皮肤的纹理特征是重要的依据,给2D照片拍照,比起给3D真人拍照,会损失一些纹理。二是频率分析 (Frequency Analysis) 。照片脸部的频率组成,也不像真人那样丰富。三是可变聚焦分析 (Variable focusing Analysis) 。连拍两张照片,聚焦在不同位置,查看像素值 (Pixel Value) 的变化。四是启发式算法 (Heuristic-Based Algorithms) 。眼动、唇动、眨眼这些动作,照片是不会有的。五是光流算法 (Optical Flow Algorithms) 。在相邻两帧之间,检测物体运动的方向和幅度,查出2D和3D物体之间的差别。……



不过这里,就把活体检测看成一个粗暴的二分类问题,这些复杂的分析先抛到一边。

自制数据集

程序猿把问题又简化了一下:这里说的“假脸”,只是“屏幕里的人脸”而已。

现在,可以开始造数据集了。

他用手机的前摄像头拍了一段25秒的视频;又举着手机、对着电脑摄像头,把视频播了一遍。



这样,一段真人视频,和一段“假脸”视频,就准备好了。

程序猿拍下的这两条视频,都提供下载。不过,他还是建议大家多收集一些数据,不同的人脸,甚至不同的人种,帮助算法茁壮成长。

下一步,要用OpenCV的人脸检测算法处理两段视频,把有用的区域 (ROI) ,就是人脸部分框出来。

这步用了80多行代码,每一行在做些什么,教程里都写清了。



最后,按照真假两个类别,把框好的脸部提取出来,就有了数据集。

温馨提示,需要平衡一下真图和假图的数量。比如,程序猿发现真实视频比假视频长,就用更大的间隔来提取。于是,他收获了真图161张,假图150张。

这数据集还是显得有些贫乏,所以后面需要扩增:旋转、翻转之类的操作,可以增加图片数量。

活体检测模型

数据集做好了,就要喂给做活体检测的神经网络。

程序猿给网络起名LivenessNet,大体长这样:



他说,这其实只是一个简单的CNN。而且,已经努力让网络保持在最浅参数最少的状态。

这样做有两个原因:一是为避免模型在小数据集上发生过拟合,二是为保证模型快到可以实时推理,就算在树莓派上也能运行。

搭个网络

现在,就来实现一下这个网络。打开livenessnet.py,再写这一段代码:

 1# import the necessary packages
 2from keras.models import Sequential
 3from keras.layers.normalization import BatchNormalization
 4from keras.layers.convolutional import Conv2D
 5from keras.layers.convolutional import MaxPooling2D
 6from keras.layers.core import Activation
 7from keras.layers.core import Flatten
 8from keras.layers.core import Dropout
 9from keras.layers.core import Dense
10from keras import backend as K
11
12class LivenessNet:
13 @staticmethod
14 def build(width, height, depth, classes):
15 # initialize the model along with the input shape to be
16 # "channels last" and the channels dimension itself
17 model = Sequential()
18 inputShape = (height, width, depth)
19 chanDim = -1
20
21 # if we are using "channels first", update the input shape
22 # and channels dimension
23 if K.image_data_format() == "channels_first":
24 inputShape = (depth, height, width)
25 chanDim = 1



然后,一层一层加上去:

 1 # first CONV => RELU => CONV => RELU => POOL layer set
 2 model.add(Conv2D(16, (3, 3), padding="same",
 3 input_shape=inputShape))
 4 model.add(Activation("relu"))
 5 model.add(BatchNormalization(axis=chanDim))
 6 model.add(Conv2D(16, (3, 3), padding="same"))
 7 model.add(Activation("relu"))
 8 model.add(BatchNormalization(axis=chanDim))
 9 model.add(MaxPooling2D(pool_size=(2, 2)))
10 model.add(Dropout(0.25))
11
12 # second CONV => RELU => CONV => RELU => POOL layer set
13 model.add(Conv2D(32, (3, 3), padding="same"))
14 model.add(Activation("relu"))
15 model.add(BatchNormalization(axis=chanDim))
16 model.add(Conv2D(32, (3, 3), padding="same"))
17 model.add(Activation("relu"))
18 model.add(BatchNormalization(axis=chanDim))
19 model.add(MaxPooling2D(pool_size=(2, 2)))
20 model.add(Dropout(0.25))

程序猿说,这个网络有点像VGGNet,很浅,过滤器 (Filter) 很少。只是判断真假,不用深度网络。

最后,再加一个FC层→RELU层的组合。

 1 # first (and only) set of FC => RELU layers
 2 model.add(Flatten())
 3 model.add(Dense(64))
 4 model.add(Activation("relu"))
 5 model.add(BatchNormalization())
 6 model.add(Dropout(0.5))
 7
 8 # softmax classifier
 9 model.add(Dense(classes))
10 model.add(Activation("softmax"))
11
12 # return the constructed network architecture
13 return model

CNN搭好了,该训练了。

训练脚本长这样

大致的训练过程,就像这张图:



打开train_liveness.py,写下这段代码:

 1# set the matplotlib backend so figures can be saved in the background
 2import matplotlib
 3matplotlib.use("Agg")
 4
 5# import the necessary packages
 6from pyimagesearch.livenessnet import LivenessNet
 7from sklearn.preprocessing import LabelEncoder
 8from sklearn.model_selection import train_test_split
 9from sklearn.metrics import classification_report
10from keras.preprocessing.image import ImageDataGenerator
11from keras.optimizers import Adam
12from keras.utils import np_utils
13from imutils import paths
14import matplotlib.pyplot as plt
15import numpy as np
16import argparse
17import pickle
18import cv2
19import os
20
21# construct the argument parser and parse the arguments
22ap = argparse.ArgumentParser()
23ap.add_argument("-d", "--dataset", required=True,
24 help="path to input dataset")
25ap.add_argument("-m", "--model", type=str, required=True,
26 help="path to trained model")
27ap.add_argument("-l", "--le", type=str, required=True,
28 help="path to label encoder")
29ap.add_argument("-p", "--plot", type=str, default="plot.png",
30 help="path to output loss/accuracy plot")
31args = vars(ap.parse_args())



导入,不停地导入

里面包含了许多的导入

有matplotlib,是可视化工具;有LivenessNet,就是刚才搭好的CNN;有train_test_split,这是scikit-learn里的函数,把数据集拆成训练集和测试集;有classification_report,也是scikit-learn里面的工具,用来生成简短统计报告的;有ImageDataGenerator,做数据扩增用的;有Adam,适合这个任务的优化器,当然也可以用SGD、RMSprop等等代替;有paths,这个模块是用来收集图片路径的;有pyplot,也是美丽的可视化工具;有numpy,是Python数学库,也是OpenCV必需品;有argparse,用来处理命令行参数;有pickle,可以把标签编码器序列化到盘上;有cv2,这是一组OpenCV Binding;还有os,这个模块用处很多,但这里只用到了它的操作系统路径分隔符而已。



梳理好这些,再看余下的代码,就会清晰很多了。

后面,是一系列的初始化,以及训练前的各种准备活动。此处略去,详见教程原文。

训练正式启动

准备就绪,运行这段命令,就可以训练了:

 1$ python train.py --dataset dataset --model liveness.model --le le.pickle
 2[INFO] loading images...
 3[INFO] compiling model...
 4[INFO] training network for 50 epochs...
 5Epoch 1/50
 629/29 [==============================] - 2s 58ms/step - loss: 1.0113 - acc: 0.5862 - val_loss: 0.4749 - val_acc: 0.7436
 7Epoch 2/50
 829/29 [==============================] - 1s 21ms/step - loss: 0.9418 - acc: 0.6127 - val_loss: 0.4436 - val_acc: 0.7949
 9Epoch 3/50
1029/29 [==============================] - 1s 21ms/step - loss: 0.8926 - acc: 0.6472 - val_loss: 0.3837 - val_acc: 0.8077
11...
12Epoch 48/50
1329/29 [==============================] - 1s 21ms/step - loss: 0.2796 - acc: 0.9094 - val_loss: 0.0299 - val_acc: 1.0000
14Epoch 49/50
1529/29 [==============================] - 1s 21ms/step - loss: 0.3733 - acc: 0.8792 - val_loss: 0.0346 - val_acc: 0.9872
16Epoch 50/50
1729/29 [==============================] - 1s 21ms/step - loss: 0.2660 - acc: 0.9008 - val_loss: 0.0322 - val_acc: 0.9872
18[INFO] evaluating network...
19 precision recall f1-score support
20
21 fake 0.97 1.00 0.99 35
22 real 1.00 0.98 0.99 43
23
24 micro avg 0.99 0.99 0.99 78
25 macro avg 0.99 0.99 0.99 78
26weighted avg 0.99 0.99 0.99 78
27
28[INFO] serializing network to 'liveness.model'...

成果斐然

训练完结,LivenessNet在验证集上拿到了99%的准确度。

当然,验证集只是热身,后面还要打开摄像头,让AI去看更多没见过的人,和没见过的“假人”。

(这一部分代码,也有详尽的解读,参见教程原文。)



就像开头展示的那样,AI能清楚地判断,它眼前的川川不是真人,而程序猿是真人。

那么,你也可以训练一只这样的AI了。

不过,不用局限于简单的二分类,可以用上前面讲到的那些复杂的分析方法,比如频率分析,比如光流法,大有可为。

教程原文传送门:

https://www.pyimagesearch.com/2019/03/11/liveness-detection-with-opencv/

源码下载入口,和无微不至的代码解析,都在里面了。



诚挚招聘

量子位正在招募编辑/记者,工作地点在北京中关村。期待有才气、有热情的同学加入我们!相关细节,请在量子位公众号(QbitAI)对话界面,回复“招聘”两个字。

量子位 QbitAI · 头条号签约作者

?'?' ? 追踪AI技术和产品新动态????

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码