阅读更多

0顶
1踩

行业应用
引用
本文来自:CSDN博客

前言

很多人都认为人脸识别是一项非常难以实现的工作,看到名字就害怕,然后心怀忐忑到网上一搜,看到网上N页的教程立马就放弃了。这些人里包括曾经的我自己。其实如果如果你不是非要深究其中的原理,只是要实现这一工作的话,人脸识别也没那么难。今天我们就来看看如何在40行代码以内简单地实现人脸识别。

一点区分

对于大部分人来说,区分人脸检测和人脸识别完全不是问题。但是网上有很多教程有无无意地把人脸检测说成是人脸识别,误导群众,造成一些人认为二者是相同的。其实,人脸检测解决的问题是确定一张图上有木有人脸,而人脸识别解决的问题是这个脸是谁的。可以说人脸检测是是人识别的前期工作。今天我们要做的是人脸识别。

所用工具

  • Anaconda 2——Python 2
  • Dlib
  • scikit-image
Dlib

对于今天要用到的主要工具,还是有必要多说几句的。Dlib是基于现代C++的一个跨平台通用的框架,作者非常勤奋,一直在保持更新。Dlib内容涵盖机器学习、图像处理、数值算法、数据压缩等等,涉猎甚广。更重要的是,Dlib的文档非常完善,例子非常丰富。就像很多库一样,Dlib也提供了python的接口,安装非常简单,用pip只需要一句即可:
pip install dlib

上面需要用到的scikit-image同样只是需要这么一句:
pip install scikit-image

注:如果用pip install dlib安装失败的话,那安装起来就比较麻烦了。错误提示很详细,按照错误提示一步步走就行了。

人脸识别

之所以用Dlib来实现人脸识别,是因为它已经替我们做好了绝大部分的工作,我们只需要去调用就行了。Dlib里面有人脸检测器,有训练好的人脸关键点检测器,也有训练好的人脸识别模型。今天我们主要目的是实现,而不是深究原理。感兴趣的同学可以到官网查看源码以及实现的参考文献。今天的例子既然代码不超过40行,其实是没啥难度的。有难度的东西都在源码和论文里。

首先先通过文件树看一下今天需要用到的东西:


准备了六个候选人的图片放在candidate-faces文件夹中,然后需要识别的人脸图片test.jpg。我们的工作就是要检测到test.jpg中的人脸,然后判断她到底是候选人中的谁。另外的girl-face-rec.py是我们的python脚本。shape_predictor_68_face_landmarks.dat是已经训练好的人脸关键点检测器。dlib_face_recognition_resnet_model_v1.dat是训练好的ResNet人脸识别模型。ResNet是何凯明在微软的时候提出的深度残差网络,获得了 ImageNet 2015 冠军,通过让网络对残差进行学习,在深度和精度上做到了比
CNN 更加强大。

1. 前期准备

shape_predictor_68_face_landmarks.dat和dlib_face_recognition_resnet_model_v1.dat都可以在这里找到。不能点击超链接的可以直接输入以下网址:http://dlib.net/files/

然后准备几个人的人脸图片作为候选人脸,最好是正脸。放到candidate-faces文件夹中。

她们分别是

然后准备四张需要识别的人脸图像,其实一张就够了,这里只是要看看不同的情况:

可以看到前两张和候选文件中的本人看起来还是差别不小的,第三张是候选人中的原图,第四张图片微微侧脸,而且右侧有阴影。

2.识别流程

数据准备完毕,接下来就是代码了。识别的大致流程是这样的:
  • 先对候选人进行人脸检测、关键点提取、描述子生成后,把候选人描述子保存起来。
  • 然后对测试人脸进行人脸检测、关键点提取、描述子生成。
  • 最后求测试图像人脸描述子和候选人脸描述子之间的欧氏距离,距离最小者判定为同一个人。
3.代码

代码不做过多解释,因为已经注释的非常完善了。以下是girl-face-rec.py
本文这里准备的是六张图片,如下:
# -*- coding: UTF-8 -*-

import sys,os,dlib,glob,numpy
from skimage import io

if len(sys.argv) != 5:
    print "请检查参数是否正确"
    exit()


# 1.人脸关键点检测器

predictor_path = sys.argv[1]

# 2.人脸识别模型

face_rec_model_path = sys.argv[2]

# 3.候选人脸文件夹

faces_folder_path = sys.argv[3]

# 4.需识别的人脸

img_path = sys.argv[4]


# 1.加载正脸检测器

detector = dlib.get_frontal_face_detector()

# 2.加载人脸关键点检测器

sp = dlib.shape_predictor(predictor_path)

# 3. 加载人脸识别模型

facerec = dlib.face_recognition_model_v1(face_rec_model_path)


# win = dlib.image_window()



# 候选人脸描述子list

descriptors = []


# 对文件夹下的每一个人脸进行:


# 1.人脸检测


# 2.关键点检测


# 3.描述子提取

for f in glob.glob(os.path.join(faces_folder_path, "*.jpg")):
    print("Processing file: {}".format(f))
    img = io.imread(f)
    #win.clear_overlay()
    #win.set_image(img)

    # 1.人脸检测
    dets = detector(img, 1)
    print("Number of faces detected: {}".format(len(dets)))

    for k, d in enumerate(dets):  
        # 2.关键点检测
        shape = sp(img, d)
        # 画出人脸区域和和关键点
        # win.clear_overlay()
        # win.add_overlay(d)
        # win.add_overlay(shape)

        # 3.描述子提取,128D向量
        face_descriptor = facerec.compute_face_descriptor(img, shape)

        # 转换为numpy array
        v = numpy.array(face_descriptor)  
        descriptors.append(v)


# 对需识别人脸进行同样处理


# 提取描述子,不再注释

img = io.imread(img_path)
dets = detector(img, 1)

dist = []
for k, d in enumerate(dets):
    shape = sp(img, d)
    face_descriptor = facerec.compute_face_descriptor(img, shape)
    d_test = numpy.array(face_descriptor) 

    # 计算欧式距离
    for i in descriptors:
        dist_ = numpy.linalg.norm(i-d_test)
        dist.append(dist_)


# 候选人名单

candidate = ['Unknown1','Unknown2','Shishi','Unknown4','Bingbing','Feifei']


# 候选人和距离组成一个dict

c_d = dict(zip(candidate,dist))

cd_sorted = sorted(c_d.iteritems(), key=lambda d:d[1])
print "\n The person is: ",cd_sorted[0][0]  
dlib.hit_enter_to_continue()
# -*- coding: UTF-8 -*-

import sys,os,dlib,glob,numpy
from skimage import io

if len(sys.argv) != 5:
    print "请检查参数是否正确"
    exit()


# 1.人脸关键点检测器

predictor_path = sys.argv[1]

# 2.人脸识别模型

face_rec_model_path = sys.argv[2]

# 3.候选人脸文件夹

faces_folder_path = sys.argv[3]

# 4.需识别的人脸

img_path = sys.argv[4]


# 1.加载正脸检测器

detector = dlib.get_frontal_face_detector()

# 2.加载人脸关键点检测器

sp = dlib.shape_predictor(predictor_path)

# 3. 加载人脸识别模型

facerec = dlib.face_recognition_model_v1(face_rec_model_path)


# win = dlib.image_window()



# 候选人脸描述子list

descriptors = []


# 对文件夹下的每一个人脸进行:


# 1.人脸检测


# 2.关键点检测


# 3.描述子提取

for f in glob.glob(os.path.join(faces_folder_path, "*.jpg")):
    print("Processing file: {}".format(f))
    img = io.imread(f)
    #win.clear_overlay()
    #win.set_image(img)

    # 1.人脸检测
    dets = detector(img, 1)
    print("Number of faces detected: {}".format(len(dets)))

    for k, d in enumerate(dets):  
        # 2.关键点检测
        shape = sp(img, d)
        # 画出人脸区域和和关键点
        # win.clear_overlay()
        # win.add_overlay(d)
        # win.add_overlay(shape)

        # 3.描述子提取,128D向量
        face_descriptor = facerec.compute_face_descriptor(img, shape)

        # 转换为numpy array
        v = numpy.array(face_descriptor)  
        descriptors.append(v)


# 对需识别人脸进行同样处理


# 提取描述子,不再注释

img = io.imread(img_path)
dets = detector(img, 1)

dist = []
for k, d in enumerate(dets):
    shape = sp(img, d)
    face_descriptor = facerec.compute_face_descriptor(img, shape)
    d_test = numpy.array(face_descriptor) 

    # 计算欧式距离
    for i in descriptors:
        dist_ = numpy.linalg.norm(i-d_test)
        dist.append(dist_)


# 候选人名单

candidate = ['Unknown1','Unknown2','Shishi','Unknown4','Bingbing','Feifei']


# 候选人和距离组成一个dict

c_d = dict(zip(candidate,dist))

cd_sorted = sorted(c_d.iteritems(), key=lambda d:d[1])
print "\n The person is: ",cd_sorted[0][0]  
dlib.hit_enter_to_continue()

4.运行结果

我们在.py所在的文件夹下打开命令行,运行如下命令
python girl-face-rec.py 1.dat 2.dat ./candidate-faecs test1.jpg

由于shape_predictor_68_face_landmarks.dat和dlib_face_recognition_resnet_model_v1.dat名字实在太长,所以我把它们重命名为1.dat和2.dat。

运行结果如下:
The person is Bingbing。

记忆力不好的同学可以翻上去看看test1.jpg是谁的图片。有兴趣的话可以把四张测试图片都运行下试试。

这里需要说明的是,前三张图输出结果都是非常理想的。但是第四张测试图片的输出结果是候选人4。对比一下两张图片可以很容易发现混淆的原因。

机器毕竟不是人,机器的智能还需要人来提升。

有兴趣的同学可以继续深入研究如何提升识别的准确率。比如每个人的候选图片用多张,然后对比和每个人距离的平均值之类的。全凭自己了。
  • 大小: 177.9 KB
  • 大小: 339.9 KB
  • 大小: 11 KB
  • 大小: 259.1 KB
0
1
评论 共 3 条 请登录后发表评论
3 楼 g21121 2017-08-01 14:23
System.out.println("人脸识别");
2 楼 QuarterLifeForJava 2017-07-26 09:17
请教下,如何看出是40行代码?
1 楼 somefuture 2017-07-25 13:43
40行?40行?

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • BGR555:BGR555颜色工具,适用于SNES、GBC、GBA

    BGR555 颜色工具 此工具可帮助您在 SNES、GBC 和 GBA 控制台使用的 RGB 十六进制代码和 15 位 BGR555 调色板格式之间进行转换。

  • 详细说明GBA的TILE方式(一)(转)

    详细说明GBA的TILE方式(一)(转)[@more@]  引言    研究GBA的TILE方式已经有些时间了。这次总结一下研究成果。    放在网上,希望可以对喜欢开发GBA软件的朋友有所帮助。    一 理论部分    1 ...

  • GBA程序开发入门3

    下面我将一一讲解上篇的程序前三行:typedef unsigned char u8;typedef unsigned short u16;typedef unsigned long u32;定义GBA程序自己的数据类型,因为这样我们就很容易知道每个数据在GBA中占的字节数.#define REG_DISPCNT *(u16*)0x04000000         // 显示

  • 时序分析基本概念介绍<GBA>

    今天我们要介绍的时序分析基本概念是GBA分析模式。全称Graph Based Analysis mode.前面文章有介绍的时序分析模式有Single,BC-WC和OCV...

  • Signoff Criteria --- ocv/aocv/pocv之AOCV介绍

    Advanced on chip variation,相比较于OCV来说,对于悲观度的去除很有效。相比较与ocv对于整个design中的lauch/capture path设置统一的derate值,aocv通过将cell derate值与cell的逻辑深度以及实际的位置结合起来进行derate值的设定。那么这种derate如何能够设置到具体的cell呢,其实是我们在跑STA时候会读入相关的aocv lib file,里面有专门对相关的cell进行的aocv derate值的描述。> table: \

  • 游戏编程--GBA探索日记

    Game Boy Advanced(GBA)是日本任天堂公司于2001年推出的一款32位掌上游戏机.它着重于游戏机的便携式,并且以2D游戏为主(3D游戏依然不错).GBA有十分高效硬件图像处理加速,GBA基本上是现在全球公认的最佳的掌上游戏机. GBA的硬件功能十分多.它的CPU是以RISC为基础的32位ARM CPU,主频是16.78MHz.屏幕最大支持240x160的16位真彩色显示.在图形处理方面GBA还另外提供了硬件加速,支持硬件上的图形旋转,缩放,alpha混合,face in/out淡入淡出等. GBA的软件开发主要是以C语言为主,程序设计简单而且十分自由,也正是这一点吸引了许多爱好者在GBA上做东西(不一定是游戏).你完全可以把它做成PDA,做成Mp3播放器(它的声音处理方面能力也不错哦),做成随身电影播放齐,做成电子词典等,只要你有能力设计它的软件.

  • 掌上游戏机开发指南GBA探索日记(10)(转)

    掌上游戏机开发指南GBA探索日记(10)(转)[@more@]  研究GBA已经有半年了,GBA上能做的东西我都研究过。什么BG,OBJ,OAM,SOUND,Interrupt都搞得很透,应该说我对GBA的认识比对PC的认识还深...

  • GBA探索日记(-)

    GBA探索日记(-)mode0-2的BG与VRAM GBA的VRAM总共96KB,在mode3-5中,VRAM跟计算机的显示内存一样.屏幕上一个点对应一个显示内存地址.可以看看下面两个函数,都是在mode4下的写点函数.void PlotPixel(int x,int y, unsigned short int c){                m_VideoBuf

  • GBA探索日记(二)

    GBA探索日记(二) OBJ及OAM OBJ就是指的一个个的精灵,或者说就是GBA中的小块小块的图片.它其实跟BG差不多.只是它要小一些.它也算个图层.比如GBA中的RPG游戏就喜欢把一个个的人物用OBJ来实现.这样方便控制他们的位置.当然,从GBA探索日记(-)中也可以看到BG的控制其实也是很方便的.而OBJ和BG的差别就是大小.   设置显示模式 如果你的程序里要用OBJ那么, 在设置显示模

  • GBA编程和汉化常用软件汇总

    内容来自GBA吧中的痴狂小黑,本人只是做个汇总和搬运。 1.简易图片导入导出套装(PicSimpleImEx & AutoPicRock)Ver1.0 这两个软件是用C#写的,想要用,先装dotNetFx40_Full_x86_x64.exe,然后重启主机; 这两个软件目前只支持GBA,格式为GBA(4BPP),今后打算支持SFC和GBA(2BPP)格式,如果想支持其他格式,可自行改

  • 【转】游戏汉化之Tile全格式解读 by 阿一

    游戏汉化之Tile全格式解读 by 阿一

  • 详细说明GBA的TILE方式(二)(转)

    详细说明GBA的TILE方式(二)(转)[@more@]  引言    上次写完(1)后,这次继续深入研究。    一 理论    1 MAP文件里的数据倒底是什么?    因为GBA里对TILE有硬件支持,所以必须有严格的格式...

  • GBA的Tile模式技术探讨--空间占用篇(转)

    GBA的Tile模式技术探讨--空间占用篇(转)[@more@]  几乎我们所知的所有2D游戏主机都采用tile模式,GBA也是如此,GBA的6种背景模式中,其中三种是tile模式,另三种是位图模式。而在任天堂的官方手册上面,很...

  • ugba:可以针对GBA硬件或PC的通用GBA库

    通用GBA库v0.1.0 1.简介 这是用于开发GBA游戏的库。 它可以用于构建实际的GBA游戏ROM,但也可以针对常规PC,因此可以更轻松地调试游戏中的逻辑。 它是用C编写的。 这意味着您可以执行以下操作: 构建GBA ROM并在仿真器中运行。 生成一个Linux可执行文件并使用GDB对其进行调试。 使用MSVC生成Windows可执行文件,然后使用Visual Studio对其进行调试。 轻松为您的游戏实施单元测试,然后在PC上运行它们。 它附带了几个示例,说明了如何使用该库的每个子系统。 所有示例也都用作单元测试,并且它们是库的自动regregr测试系统的一部分。 通过向程序传递带有说明的Lua脚本,可以简单地在主机上运行测试的PC版本。 GBA构建在上运行,该也具有对Lua脚本的基本支持。 理想情况下,它将在其他仿真器上进行测试。 PC版本内部具有仿真器的某些部分,以

  • GBA硬件规格与系统参数

    GBA硬件规格(第一部分CPU,内存) 原来想一口气把声音,输入控制,中断,DMA的例程都写出来,我的例程都是编译通过的。现在看来应该先把GBA的硬件规格先写出来。 GBA硬件规格(第一部分CPU,内存) GBA系统由以下部分组成: CPU -16.78MHz ARM/tdmi 内存-根据应用的情况,有8-11个内存分区,有的是只读的,有的是可写的,详细见后。 输入输出-系统提供了图形,声音,DM

  • 从GBA开始,步入ARM开发的殿堂(初学者入门篇)

    GBA开始,步入ARM开发的殿堂(初学者入门篇)1.为什么要选用GBA作为嵌入式系统学习平台我们知道,任天堂公司的GameBoy Advance(简称GBA)一款非常出色的掌上游戏机,该产品占领了全球90%以上的掌上游戏机市场。抛开游戏功能不说,GBA本身就是一个很好的嵌入式系统开发学习平台,因为GBA采用ARM7 CPU(RISC),拥有240×160 64K色彩色液晶、立体声系统、按键、DMA

  • GBA探索日记(-) (转)

    GBA探索日记(-) (转)[@more@]GBA探索日记(-)XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" /&gt; mod...

Global site tag (gtag.js) - Google Analytics