python的python做人脸识别别的APP吗

  人脸识别是什么?或识别是什麼?当你看到一个苹果时你的大脑会立刻告诉你这是一个苹果。在这个过程中你的大脑告诉你这是一个苹果水果,用简单的语言来说就昰识别那么什么是人脸识别呢?我肯定你猜对了。当你看着你的朋友走在街上或他的照片时你会认出他是你的朋友保罗。有趣的是当伱看你的朋友或他的照片时,你首先要看他的脸然后再看其他东西。你想过为什么要这么做吗?这是为了让你看他的脸就能认出他来好吧,这是你的面部识别

  但真正的问题是人脸识别是如何工作的?它非常简单和直观。举一个现实生活中的例子当你在生活中第一次遇见一个人,你不认识他对吧?当他和你说话或握手时,你看着他的脸、眼睛、鼻子、嘴巴、颜色和整体的表情这是你通过收集面部数據来学习或训练那个人的面部识别。然后他告诉你他叫保罗此时,你的大脑知道它刚刚学到的面部数据属于保罗现在你的头脑已经训練好了,准备在保罗的脸上做面部识别下次当你在照片中看到保罗或他的脸时,你会立刻认出他这就是人脸识别的工作原理。你遇到保罗的次数越多你的大脑就会收集到更多关于他的信息,尤其是他的脸你就越能识别他。

  下一个问题是如何用OpenCV编码人脸识别毕竟这是你阅读这篇文章的唯一原因,对吧?那么,好吧你可能会说我们的大脑可以很容易地做这些事情,但是把它们编码到电脑里是很困难嘚吗?别担心不是的。多亏了OpenCV编码人脸识别变得越来越容易。人脸识别的编码步骤与我们在上面的实际示例中讨论的一样

  ·训练數据收集:收集您想要识别的人的面部数据(本例中为面部图像)

  ·识别器的训练:将人脸数据(以及每个人脸的相应名称)输入人脸识别器,使其能够学习

  ·识别:输入这些人的新面孔,看看你刚训练过的人脸识别器是否识别他们

OpenCV带有内置的人脸识别器你所要做的就是给它輸入人脸数据。这很简单一旦我们完成了编码,它就会看起来很简单

  OpenCV有三个内置的人脸识别器,多亏了OpenCV干净的编码你可以通过妀变一行代码来使用它们中的任何一个。下面是这些人脸识别器的名称和它们的OpenCV调用

  现在我们有三个人脸识别器但是你知道该用哪┅个吗?什么时候用吗或者哪个更好?我猜你不知道那么,接下来我们将深入研究每一个识别器

  这个算法考虑的事实是,并不昰脸的所有部分都同样重要或同样有用。当你看一个人的时候你会通过他独特的特征认出他/她,比如眼睛、鼻子、脸颊、前额以及他們之间的差异所以你实际上关注的是最大变化的区域(数学上说,这个变化是方差)例如,从眼睛到鼻子有一个显著的变化从鼻子到嘴吔是如此。当你看多张脸的时候你可以通过看脸的这些部分来比较它们因为这些部分是脸最有用和最重要的组成部分重要的是,它们捕捉到人脸之间的最大变化这种变化可以帮助你区分不同的人脸,这就是特征人脸识别系统的工作原理

  EignFaces人脸识别器将所有人的训练圖像作为一个整体,并试图提取重要和有用的成分(捕捉最大方差/变化的成分)并丢弃其余的成分。这样它不仅从训练数据中提取重要的組件,而且通过丢弃不重要的组件来节省内存它提取的这些重要成分被称为主成分。

  我所用主成分方差,高变化区域可互换的囿用特征等术语,它们的性质基本上是一样的东西
  以下是显示从面部列表中提取的主要组件的图像。

  你可以看到主分量实际仩表示面的,这些面被称为特征面也就是算法的名字。

  这就是特征面识别器自身的训练方式(通过提取主成分)它还记录了哪个主成汾属于哪个人。在上面的图像中需要注意的一点是特征面算法也将光照作为一个重要的组成部分

  在随后的识别过程中,当你向算法輸入新图像时它也会在该图像上重复同样的过程。它从新映像中提取主组件并将该组件与它在训练期间存储的组件列表进行比较,并找到匹配最好的组件并返回与该最佳匹配组件关联的person标签。

  轻松+容易对吧? 下一个比这个更容易

  该算法是改进后的FisherFaces人脸识別算法。FisherFaces人脸识别器同时查看所有人的训练面并从所有人的训练面中找到主要的组成部分。通过从所有的人脸中捕获主要的组成部分伱并没有把注意力集中在区分一个人和另一个人的特征上,而是集中在代表整个训练数据中所有人的所有面孔的特征上

  这种方法有┅个缺点。 例如考虑下面的面光照变化。

  你知道特征面人脸识别器也认为照明是一个重要的组成部分对吧?想象一个场景,一个人所有的脸都有非常高的亮度变化(非常暗或者非常亮等等)特征人脸识别者将会考虑这些光照变化非常有用的特征,并且可能会忽略其他人嘚面部特征认为这些特征不太有用。现在所提取的特征特征面只代表一个人的面部特征而不是所有人的面部特征。

  如何解决这个問题 我们可以通过调整EigenFaces人脸识别器来解决这个问题,以便从每个人的脸部分别提取有用的特征而不是提取所有脸部组合的有用特征。 這样即使一个人的光照变化很大,也不会影响其他人物特征提取过程 这正是FisherFaces人脸识别器算法的功能。

  Fisherfaces算法不是提取表示所有人员所有面部的有用特征而是提取可区分一个人和另一个人的有用特征。 通过这种方式一个人的特征不会占据主导地位(被认为是更有用嘚特征)而其他人则具有区分一个人和另一个人的特征。

下面是使用Fisherfaces算法提取的特征的图像

   你可以看到提取的特征实际上代表了面孔,这些面被称为Fisher faces因此算法的名称。

  这里需要注意的一点是Fisherfaces人脸识别器只会阻止一个人的特征凌驾于另一个人的特征之上,但它仍然认为光照变化是有用的特征我们知道光照变化不是一个有用的特征来提取,因为它不是真正的脸的一部分那么,该怎么摆脱这个照明问题?这就是我们的下一个人脸识别器锁解决的问题

 局部二值模式直方图(LBPH)人脸识别器

  我们知道Eigenfaces和Fisherfaces都受光线影响,在现实生活中峩们无法保证完美的光照条件。 LBPH人脸识别器是克服这个缺点的一种改进

  这种想法是不看整个图像,而是查找图像的局部特征 LBPH算法試图找出图像的局部结构,并通过比较每个像素与其相邻像素来实现

  取一个3x3的窗口,每移动一个图像(图像的每个局部)将中心的像素与相邻像素进行比较。强度值小于或等于中心像素的邻域用1表示其它邻域用0表示。然后你以顺时针的顺序读取3x3窗口下的0/1值你会得到┅个像这样的二进制模式,这个模式在图像的特定区域是局部的在整个图像上这样做,就会得到一个局部二进制模式的列表

  现在伱明白为什么这个算法的名字中有局部二进制模式? 因为你得到一个局部二进制模式列表 现在你可能想知道,LBPH的直方图部分呢 在获得局部二进制模式列表后,您可以使用二进制到十进制转换将每个二进制模式转换为十进制数(如上图所示)然后对所有这些十进制值进荇直方图制作。 样本直方图是像下面这样的

  我猜这回答了直方图部分的问题。所以最终你会得到训练数据集中每个人脸图像的一个矗方图这意味着如果训练数据集中有100个图像,那么LBPH会在训练后提取100个直方图并储存起来以便以后识别。记住算法也会跟踪哪个直方圖属于哪个人。

  在识别后期当您将新图像送入识别器进行识别时,它将生成新图像的直方图将该直方图与其已有的直方图进行比較,找到最佳匹配直方图并返回与该最佳匹配关联的人员标签 匹配直方图

  下面是一张脸和它们各自的局部二进制模式图像的列表。您可以看到LBP图像不受光照条件变化的影响。

  理论部分已经结束现在是编码部分!准备好开始编写代码了吗?那我们开始吧。

使用OpenCV编码囚脸识别

  本教程中的人脸识别过程分为三个步骤

  1、准备训练数据:在这一步中,我们将读取每个人/主体的训练图像及其标签從每个图像中检测人脸并为每个检测到的人脸分配其所属人员的整数标签。

  2、训练人脸识别器:在这一步中我们将训练OpenCV的LBPH人脸识别器,为其提供我们在步骤1中准备的数据

  3、测试:在这一步中,我们会将一些测试图像传递给人脸识别器并查看它是否能够正确预測它们

   :Numpy使Python中的计算变得容易。 除此之外它还包含一个强大的N维数组实现,我们将使用它来将数据作为OpenCV函数的输入

  在开始实际编码之前,我们需要导入所需的编码模块 所以让我们先导入它们。

  cv2:是Python的OpenCV模块我们将用它来进行人脸检测和人脸识别。

  os:我们将使用这个Python模块来读取我们的培训目录和文件名

  numpy:我们将使用此模块将Python列表转换为numpy数组,因为OpenCV人脸识别器接受numpy数组

#导入os模块用于读取训练数据目录和路径

  训练中使用的图像越多越好。 通常很多图像用于训练面部识别器以便它可以学习同一个人的不同外观,例如戴眼镜不戴眼镜,笑伤心,快乐哭泣,留着胡子没有胡子等。 简单的教程我们将只为每个人使用12张图片

  所以我們的训练数据由共2人组成,每个人有12张图像 所有培训数据都在培训数据文件夹内。 训练数据文件夹包含每个人的一个文件夹并且每个攵件夹以格式sLabel(例如s1,s2)命名其中标签实际上是分配给该人的整数标签。 例如名为s1的文件夹意味着该文件夹包含人员1的图像。培训数據的目录结构树如下所示:

  测试数据文件夹包含我们将用于在成功培训完成后测试人脸识别器的图像

  由于OpenCV人脸识别器接受标签为整数因此我们需要定义整数标签和人物实际名称之间的映射,所以下面我定义了人员整数标签及其各自名称的映射

  注意:由于我們尚未将标签0分配给任何人,因此标签0的映射为空

#我们的训练数据中没有标签0,因此索引/标签0的主题名称为空
 

  您可能想知道为什么偠进行数据准备对吗? 那么OpenCV人脸识别器接受特定格式的数据。 它接受两个矢量一个矢量是所有人的脸部,第二个矢量是每个脸部的整数标签因此在处理脸部时,脸部识别器会知道该脸部属于哪个人

  例如,如果我们有两个人和两个图像为每个人

  然后,准備数据步骤将生成以下面和标签向量

  准备数据步骤可以进一步分为以下子步骤。

  1、阅读培训数据文件夹中提供的所有主题/人员嘚文件夹名称 例如,在本教程中我们有文件夹名称:s1,s2

  2、对于每个主题,提取标签号码 你还记得我们的文件夹有一个特殊的命名约定吗? 文件夹名称遵循格式sLabel其中Label是一个整数,代表我们已分配给该主题的标签 因此,例如文件夹名称s1表示主题具有标签1,s2表礻主题标签为2等 将在此步骤中提取的标签分配给在下一步中检测到的每个面部。

  3、阅读主题的所有图像从每张图像中检测脸部。

  4、将添加到标签矢量中的具有相应主题标签(在上述步骤中提取)的每个脸部添加到脸部矢量

#使用OpenCV用来检测脸部的函数
 #将测试图像轉换为灰度图像,因为opencv人脸检测器需要灰度图像
 
 #加载OpenCV人脸检测器我正在使用的是快速的LBP
 #还有一个更准确但缓慢的Haar分类器
 #让我们检测多尺喥(一些图像可能比其他图像更接近相机)图像
 
 #如果未检测到面部,则返回原始图像
 
 
 #只返回图像的正面部分
 

在第20行中从检测到的脸部我呮挑选第一张脸部,因为在一张图像中只有一张脸部(假设只有一张醒目的脸部) 由于detectMultiScale方法返回的面实际上是矩形(x,y宽度,高度)而不是实际的面部图像,所以我们必须从主图像中提取面部图像区域 所以在第23行我从灰色图像中提取人脸区域并返回人脸图像区域和囚脸矩形。

  现在您已经有了一个面部检测器您知道准备数据的4个步骤,那么您准备好编写准备数据步骤了吗?是吗?让我们来做它

#该功能将读取所有人的训练图像,从每个图像检测人脸
#并将返回两个完全相同大小的列表一个列表 
# 每张脸的脸部和另一列标签
 
 #获取数据文件夹中的目录(每个主题的一个目录)
 
 #列表来保存所有主题的面孔
 #列表以保存所有主题的标签
 
 #让我们浏览每个目录并阅读其中的图像
 
 #我们嘚主题目录以字母's'开头
 #如果有的话,忽略任何不相关的目录
 
 #从dir_name中提取主题的标签号
 #所以从dir_name中删除字母''会给我们标签
 
 #建立包含当前主题主題图像的目录路径
 
 #获取给定主题目录内的图像名称
 
 #浏览每个图片的名称,阅读图片
 #检测脸部并将脸部添加到脸部列表
 
 
 
 #显示图像窗口以显礻图像
 
 
 #我们将忽略未检测到的脸部
 
 
 

我已经定义了一个函数,它将存储培训主题文件夹的路径作为参数 该功能遵循上述的4个准备数据子步驟。

(step--1)在第8行我使用os.listdir方法读取存储在传递给函数的路径上的所有文件夹的名称作为参数。 在第10-13行我定义了标签并面向矢量。

(step--2)之後我遍历所有主题的文件夹名称以及第27行中每个主题的文件夹名称,我将提取标签信息 由于文件夹名称遵循sLabel命名约定,所以从文件夹洺称中删除字母将给我们分配给该主题的标签

waitKey(interval)方法将代码流暂停给定的时间间隔(毫秒),我以100ms的间隔使用它以便我们可以查看100ms嘚图像窗口。 在第57行我从当前正在遍历的图像中检测出脸部。

(step--4)在第62-66行我将检测到的面和标签添加到它们各自的向量中。

  但是┅个函数只能在需要准备的某些数据上调用它时才能做任何事情对吗? 别担心我有两张脸的数据。 我相信你至少会认出其中的一个!

讓我们在这些美丽的名人的图像上调用这个函数来准备数据来训练我们的人脸识别器 下面是一个简单的代码来做到这一点。

#让我们先准備好我们的训练数据
#数据将在两个相同大小的列表中
#一个列表将包含所有的面孔
#数据将在两个相同大小的列表中
 

  这可能是最无聊的部汾对吧?别担心,接下来会有有趣的事情发生现在是时候训练我们自己的人脸识别器了,这样一旦训练它就能识别它所训练的人的新面孔了读吗?那我们来训练我们的人脸识别器。

 我们知道OpenCV配备了三个人脸识别器。

  我将使用LBPH人脸识别器但您可以使用您选择的任何囚脸识别器。 无论您使用哪个OpenCV的脸部识别器其代码都将保持不变。 您只需更改一行即下面给出的面部识别器初始化行。

#创建我们的LBPH人臉识别器
 

  现在我们已经初始化了我们的人脸识别器也准备了我们的训练数据,现在是时候训练人脸识别器了我们将通过调用人脸識别器的序列(面向量,标签向量)方法来实现这一点

#训练我们的面部识别器
 

  你有没有注意到,不是直接将标签矢量直接传递给人脸识別器而是先把它转换成numpy数组?这是因为OpenCV希望标签向量是一个numpy数组。

  仍然不满意 想看到一些行动? 下一步是真正的行动我保证!

  现在是我最喜欢的部分,预测部分 这是我们真正了解我们的算法是否确实能够识别受过训练的对象脸部的地方。 我们将拍摄两张我们嘚景点的测试图像从他们每个人身上检测脸部,然后将这些脸部传递给我们训练有素的脸部识别器看看它们是否识别它们。

  下面昰一些实用功能我们将用它来绘制围绕脸部的边界框(矩形)并将边界名称放在边界框附近。

#函数在图像上绘制矩形
#根据给定的(xy)唑标和
 
#函数在从图像开始绘制文本
#通过(x,y)坐标
 

  既然我们有绘图功能,我们只需要调用人脸识别器预测(人脸)方法来测试我们嘚测试图像上的人脸识别器 以下功能为我们做了预测。

#制作图像的副本因为我们不想更改原始图像 #使用我们的脸部识别器预测图像 #获取由人脸识别器返回的相应标签的名称 #在检测到的脸部周围画一个矩形

第7行从测试图像中检测脸部
第11行通过调用面部识别器的预测(面部)方法来识别面部。 该方法将返回一个标签
第12行获取与标签关联的名称
第16行在检测到的脸部周围绘制矩形
第18行绘制预测主体在面部矩形上方的名称

  现在我们已经很好地定义了预测函数下一步就是在我们的测试图像上实际调用这个函数,并显示这些测试图像以查看我们嘚人脸识别器是否能正确识别它们 所以让我们来做。 这就是我们一直在等待的

  你可以从这个Github下载完整的代码和相关文件 .

  人脸識别是一个非常有趣的想法,OpenCV使得它非常简单易于我们对其进行编码。 只需几行代码即可完成全面工作的人脸识别应用程序并且我们鈳以通过一行代码更改在所有三个人脸识别器之间切换。 就这么简单

  尽管EigenFaces,FisherFaces和LBPH人脸识别器都不错但是使用面向梯度直方图(HOG)和鉮经网络进行人脸识别还有更好的方法。 因此更先进的人脸识别算法现在是一个使用OpenCV和机器学习相结合的日子。 我还计划写一些关于这些更高级方法的文章敬请关注!

}

我要回帖

更多关于 python做人脸识别 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信