有一张人脸的侧脸图像,如何用python及相关的库来计算人脸转过的角度。

Python023

有一张人脸的侧脸图像,如何用python及相关的库来计算人脸转过的角度。,第1张

这个很难办到,不过可以通过判断关键点的特点进行判断,但是准确率不高

前言

很多人都认为人脸识别是一项非常难以实现的工作,看到名字就害怕,然后心怀忐忑到网上一搜,看到网上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都可以在这里找到。

然后准备几个人的人脸图片作为候选人脸,最好是正脸。放到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()

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。对比一下两张图片可以很容易发现混淆的原因。

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

有兴趣的同学可以继续深入研究如何提升识别的准确率。比如每个人的候选图片用多张,然后对比和每个人距离的平均值之类的。全凭自己了。

理论

我们看到了一些特征检测算法,他们很多都不错,但是从实时应用的角度看,他们都不够快,一个最好的例子是SLAM(同步定位与地图创建)移动机器人没有足够的计算能力。

作为解决方案,FAST(加速切片测试特征)算法被提出,Edward Rosten和Tom Drummond 2006年在他们的论文“Machine learning for high-speed corner detection”提出,并在2010年最后修订,算法的基本大意如下:

使用FAST进行特征检测

1.选择一个图像里的像素p用来识别是不是一个兴趣点,它的强度是Ip

2.选择一个合适的阈值t

3.在要测试的像素周围找16个像素的圆

4.现在如果存在一个在圆内(16像素的)的n个连续像素集合,他们都比Ip + t要亮,或者都比Ip - t 要暗(用白虚线显示),那p就是角, n取12。

5.用一个高速测试来排除大量非角。这个测试只检查1,9,5和13位置的像素(首先1和9会测试是否他们太亮或者太暗,如果是,再检查5和13)。如果p是角,那么至少3个都比Ip+t要亮或者比Ip-t要暗,如果不是这样,那么p不可能是角。这个检测器展现了高性能,但是有几个缺陷:

·当n<12时不能拒绝很多备选点

·像素的选择不是可选的,因为它的效率依赖问题和角的分布。

·高速测试的结果被丢弃了

·会检测出多个爱挨在一起的特征

机器学习角点检测

1.选择一组图像进行训练(最好从目标应用范围内)

2.运行FAST算法来对每个图像进行特征点查找

3.对每个特征点,存下周围的16个像素作为向量。所有图像做完以后得到特征向量P。

4.这16个像素里的每个像素(设为x)可以有下面的三个状态:

5.根据这些状态,特征向量P被分成3个子集,Pd, Ps, Pb.

6.定义个新的布尔变量Kp,如果p是角就是真反之为假。

7.使用ID3算法(决策树分类)来查询每个子集,对于每个true类用变量Kp,它选择x来得出一个备选像素是否是角的信息。

8.对所有子集迭代直到为0

9.创建的决策树用来对其他图形做fast检测

非极大值抑制

在临近位置检测多个兴趣点是另一个问题,可以使用非极大值抑制来解决。

1.计算一个分数函数,V是所有检测到的特征点,V是p和16个围着的像素值得绝对差。

2.计算两个相邻关键点的V值

3.丢掉V值低的那个

总结:

它比其他存在的角点算法要快几倍

但是它对高噪点情况来说不健壮,依赖阈值

OpenCV里的FAST特征检测

它和其他OpenCV里的特征检测类似,如果你愿意,你可以指定阈值,是否使用非极大值抑制,要用的邻居等。

对于邻居,定义了三个标志位, cv2.FAST_FEATURE_DETECTOR_TYPE_5_8, cv2.FAST_FEATURE_DETECTOR_TYPE_7_12和cv2.FAST_FEATURE_DETECTOR_TYPE_9_16.

看结果,第一个图像显示了使用了非极大值抑制的FAST,第二个是没有使用非极大值抑制的。

END

PIL (Python Imaging Library)

Python图像处理库,该库支持多种文件格式,提供强大的图像处理功能。

PIL中最重要的类是Image类,该类在Image模块中定义。

从文件加载图像:

如果成功,这个函数返回一个Image对象。现在你可以使用该对象的属性来探索文件的内容。

format 属性指定了图像文件的格式,如果图像不是从文件中加载的则为 None 。

size 属性是一个2个元素的元组,包含图像宽度和高度(像素)。

mode 属性定义了像素格式,常用的像素格式为:“L” (luminance) - 灰度图, “RGB” , “CMYK”。

如果文件打开失败, 将抛出IOError异常。

一旦你拥有一个Image类的实例,你就可以用该类定义的方法操作图像。比如:显示

( show() 的标准实现不是很有效率,因为它将图像保存到一个临时文件,然后调用外部工具(比如系统的默认图片查看软件)显示图像。该函数将是一个非常方便的调试和测试工具。)

接下来的部分展示了该库提供的不同功能。

PIL支持多种图像格式。从磁盘中读取文件,只需使用 Image 模块中的 open 函数。不需要提供文件的图像格式。PIL库将根据文件内容自动检测。

如果要保存到文件,使用 Image 模块中的 save 函数。当保存文件时,文件名很重要,除非指定格式,否则PIL库将根据文件的扩展名来决定使用哪种格式保存。

** 转换文件到JPEG **

save 函数的第二个参数可以指定使用的文件格式。如果文件名中使用了一个非标准的扩展名,则必须通过第二个参数来指定文件格式。

** 创建JPEG缩略图 **

需要注意的是,PIL只有在需要的时候才加载像素数据。当你打开一个文件时,PIL只是读取文件头获得文件格式、图像模式、图像大小等属性,而像素数据只有在需要的时候才会加载。

这意味着打开一个图像文件是一个非常快的操作,不会受文件大小和压缩算法类型的影响。

** 获得图像信息 **

Image 类提供了某些方法,可以操作图像的子区域。提取图像的某个子区域,使用 crop() 函数。

** 复制图像的子区域 **

定义区域使用一个包含4个元素的元组,(left, upper, right, lower)。坐标原点位于左上角。上面的例子提取的子区域包含300x300个像素。

该区域可以做接下来的处理然后再粘贴回去。

** 处理子区域然后粘贴回去 **

当往回粘贴时,区域的大小必须和参数匹配。另外区域不能超出图像的边界。然而原图像和区域的颜色模式无需匹配。区域会自动转换。

** 滚动图像 **

paste() 函数有个可选参数,接受一个掩码图像。掩码中255表示指定位置为不透明,0表示粘贴的图像完全透明,中间的值表示不同级别的透明度。

PIL允许分别操作多通道图像的每个通道,比如RGB图像。 split() 函数创建一个图像集合,每个图像包含一个通道。 merge() 函数接受一个颜色模式和一个图像元组,然后将它们合并为一个新的图像。接下来的例子交换了一个RGB图像的三个通道。

** 分离和合并图像通道 **

对于单通道图像, split() 函数返回图像本身。如果想处理各个颜色通道,你可能需要先将图像转为RGB模式。

resize() 函数接受一个元组,指定图像的新大小。

rotate() 函数接受一个角度值,逆时针旋转。

** 基本几何变换 **

图像旋转90度也可以使用 transpose() 函数。 transpose() 函数也可以水平或垂直翻转图像。

** transpose **

transpose() 和 rotate() 函数在性能和结果上没有区别。

更通用的图像变换函数为 transform() 。

PIL可以转换图像的像素模式。

** 转换颜色模式 **

PIL库支持从其他模式转为“L”或“RGB”模式,其他模式之间转换,则需要使用一个中间图像,通常是“RGB”图像。

ImageFilter 模块包含多个预定义的图像增强过滤器用于 filter() 函数。

** 应用过滤器 **

point() 函数用于操作图像的像素值。该函数通常需要传入一个函数对象,用于操作图像的每个像素:

** 应用点操作 **

使用以上技术可以快速地对图像像素应用任何简单的表达式。可以结合 point() 函数和 paste 函数修改图像。

** 处理图像的各个通道 **

注意用于创建掩码图像的语法:

Python计算逻辑表达式采用短路方式,即:如果and运算符左侧为false,就不再计算and右侧的表达式,而且返回结果是表达式的结果。比如 a and b 如果a为false则返回a,如果a为true则返回b,详见Python语法。

对于更多高级的图像增强功能,可以使用 ImageEnhance 模块中的类。

可以调整图像对比度、亮度、色彩平衡、锐度等。

** 增强图像 **

PIL库包含对图像序列(动画格式)的基本支持。支持的序列格式包括 FLI/FLC 、 GIF 和一些实验性的格式。 TIFF 文件也可以包含多个帧。

当打开一个序列文件时,PIL库自动加载第一帧。你可以使用 seek() 函数 tell() 函数在不同帧之间移动。

** 读取序列 **

如例子中展示的,当序列到达结尾时,将抛出EOFError异常。

注意当前版本的库中多数底层驱动只允许seek到下一帧。如果想回到前面的帧,只能重新打开图像。

以下迭代器类允许在for语句中循环遍历序列:

** 一个序列迭代器类 **

PIL库包含一些函数用于将图像、文本打印到Postscript打印机。以下是一个简单的例子。

** 打印到Postscript **

如前所述,可以使用 open() 函数打开图像文件,通常传入一个文件名作为参数:

如果打开成功,返回一个Image对象,否则抛出IOError异常。

也可以使用一个file-like object代替文件名(暂可以理解为文件句柄)。该对象必须实现read,seek,tell函数,必须以二进制模式打开。

** 从文件句柄打开图像 **

如果从字符串数据中读取图像,使用StringIO类:

** 从字符串中读取 **

如果图像文件内嵌在一个大文件里,比如 tar 文件中。可以使用ContainerIO或TarIO模块来访问。

** 从tar文档中读取 **

** 该小节不太理解,请参考原文 **

有些解码器允许当读取文件时操作图像。通常用于在创建缩略图时加速解码(当速度比质量重要时)和输出一个灰度图到激光打印机时。

draft() 函数。

** Reading in draft mode **

输出类似以下内容:

注意结果图像可能不会和请求的模式和大小匹配。如果要确保图像不大于指定的大小,请使用 thumbnail 函数。

Python2.7 教程 PIL

http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00140767171357714f87a053a824ffd811d98a83b58ec13000

Python 之 使用 PIL 库做图像处理

http://www.cnblogs.com/way_testlife/archive/2011/04/17/2019013.html

来自 http://effbot.org/imagingbook/introduction.htm