40行代码的人脸识别实践

点击上方

Python开发

”,选择“置顶公众号”

关键时刻,第一时间送达!

40行代码的人脸识别实践

40行代码的人脸识别实践

前言

很多人都认为人脸识别是一项非常难以实现的工作,看到名字就害怕,然后心怀忐忑到网上一搜,看到网上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行,其实是没啥难度的。有难度的东西都在源码和论文里。

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

    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

     文件夹中。

    本文这里准备的是六张图片,如下:

    40行代码的人脸识别实践

    她们分别是

    40行代码的人脸识别实践

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

    40行代码的人脸识别实践

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

    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

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

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

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

    40行代码的人脸识别实践

  • 作者:刘潇龙

  • 原文:http://www.qcloud.com/community/article/552472001490775222

  • Python开发整理发布,转载请联系作者获得授权

  • 40行代码的人脸识别实践

    40行代码的人脸识别实践

    【点击成为Java大神】