2018-12-14 20:41:49 zijin0802034 阅读数 10186
  • 卷积神经网络与人脸识别系统实战视频教程

    卷积神经网络与人脸识别系统实战视频培训课程概况:本教程从零开始讲解人工神经网络,卷积神经网络等基础内容,然后讲解基于python如何构建一个深度学习模型,后基于CNN,利用keras构建网络结构打造一个人脸识别系统。

    2558 人正在学习 去看看 王而川

简介

我们经常能从电影中看到各种神奇的人脸识别技术,例如图1。人脸识别技术是基于面部特征信息进行身份识别的一种生物识别技术。该技术在图片/视频中,从人脸的角度入手,识别出画面中的人物是谁。如图2所示,严格来讲,这个过程包括人脸检测 (face detection) ,人脸对齐(face alignment) ,人脸识别 (face recognition) 三个部分。人脸检测目的是从图片/视频中,找到人脸,并确定人脸的位置; 人脸对齐目的是找到人的面部特征点(鼻子,眼睛,嘴巴等),解决人脸的角度变化问题;人脸识别目的是识别人脸,确定身份。本文我们只关注人脸识别这部分工作。

人脸识别是一个历史悠久的任务,从20世纪50年代开始,研究人员已经开始关注人脸识别这个领域。从最早基于人脸几何结构特征,到基于建模方法,局部特征描述子(Gabor, LBP),目前主流的方法是基于深度学习的方法。自从2012年,AlexNet [1] 以巨大领先优势获得ImageNet第一名以后,研究人员来开始思考是否能够用深度学习方法来做人脸识别的任务。高性能计算机 (CPU, GPU) 出现,大规模人脸数据集出现 (LFW [2] ,CISIA-WebFace [3] , MS-Celeb-1M [4]) ,加上对人脸识别问题的深刻理解,基于深度学习的人脸识别算法将人脸识别精度提高了一个新的台阶。损失函数是CNN (卷积神经网络) 重要组成部分,它指导了网络的优化目标。本文从损失函数入手,简单介绍基于CNN的人脸识别的损失函数的原理以及发展过程。
在人脸识别中,每个人都可以看做一类,直观的想法可以用分类算法来做。但是,不同于分类算法,人脸数据集一般个人(类别)较多,每个人的样本却不多,并且样本不能覆盖所有人,测试的时候很多情况会出现训练集中不存在的样本。基于此,通用的方法把人脸识别看做一个距离度量的问题,通过学习样本的特征,然后计算样本之间的距离,来确定人物身份。本文主要介绍以下四种常用的损失函数:Contrastive Loss[5],Triplet Loss [6], Center loss [7]和 A-Softmax loss [8]。

Contrastive Loss

早在2005年,Chopra[5]就提出了Contrastive loss就用来解决人脸验证/识别问题。首先,作者从人脸数据集,选出若干对人脸,构成人脸二元组。这样的人脸二元组包括两种情况:属于同一个人;属于不同的人,见图3。如果一个人脸对属于同一个人,标记这种人脸对的标签Y=0,如果一对人脸中,属于不同的人,那么标记这种人脸对的标签Y=1。这样做还有一个好处,能够扩充数据集,支持CNN的训练。以论文中的AT&T Database of Faces [9] 为例,一共400张图片,40个人,每个人10张图片。同一个人的人脸二元组有4000个,不同人的人脸二元组有156000个,一定程度上更满足CNN大规模训练数据要求。

为了方便阐述,我把论文中的网络结构也放到这里,如图4所示:

Contrastive loss 定义如下:
l(W)=i=1PL(W,(Y,X1,X2)i)l(W)=∑_{i=1}^P L(W,(Y,X_1,X_2 )^i)

L(W,(Y,X1,X2)i)=(1Y)LG(EW(X1,X2)i)+YLI(EW(X1,X2)i)L(W,(Y,X_1,X_2 )^i )=(1-Y) L_G (E_W (X_1,X_2 )^i )+YL_I (E_W (X_1,X_2 )^i)

这里W表示网络的参数,(Y,X1,X2)(Y,X_1,X_2) 表示第i个人脸二元组, LGL_G表示属于同一类的部分损失函数, LIL_I表示属于不同人脸的损失函数, P是训练的人脸二元组的数目。LGL_G这里 是一个单调递增的函数, LIL_I是一个单调递减的函数。一个最简单的例子LG(x)=x,LI(x)=xL_G(x)=x,L_I(x)=-x , 那么上述损失函数L变为:
L(W,(Y,X1,X2)i)=(1Y)EW(X1,X2)iY(EW(X1,X2)i))L(W,(Y,X_1,X_2 )^i )=(1-Y) E_W (X_1,X_2 )^i-Y(E_W (X_1,X_2 )^i))

如果Y = 0,表示输入的是属于同一个人的人脸二元组,后面一项为0,最小化损失函数L让EW(X1,X2)E_W(X_1,X_2)最 小,既是类内的距离尽可能小。当Y = 1时,表示输入的人脸二元组属于不同的人,前面的一项为0,最小化损失函数L,等价于EW(X1,X2)E_W(X_1,X_2)变大,既是类间的距离尽可能大。以上过程就是contrastive loss 函数。

Triplet Loss

FaceNet [6] 文中提出了Triplet Loss,与Contrastive loss的输入二元组不同的是,Triplet输入时人脸三元组。随机从某个人照片中选择一张,叫做Anchor;再从这个人照片中选择另一个照片,叫做Positive;最后随机选择一张其他人的照片,叫做Negative, 这样就构成了图像的三元组。图5就是三元组的一个例子。

人脸识别的优化目标是同一个人距离尽可能近,不同人的距离尽可能远。假设Xia,Xip,XinX_i^a,X_i^p,X_i^n 分别代表第i个三元组的Anchor,正例,负例。 f(Xia),f(Xip),f(Xin)f(X_i^a),f(X_i^p),f(X_i^n)分别代表对应的特征。Triplet Loss损失函数如下所示:
L=iN[f(xia)f(xip)22f(xia)f(xin)22+α]+L= ∑_i^N [∥f(x_i^a )-f(x_i^p )∥_2^2-∥f(x_i^a )-f(x_i^n )∥_2^2+α]_+

表示[]内的值如果大于零的时候,损失等于该值,小于零的时候,损失等于0。 α\alpha 是超参数,表示Anchor和Positive特征距离应该比Anchor和Negative的特征距离大于 。最小化上述损失函数,就能保证同一个人脸特征距离小于不同人的人脸特征距离了。

Center Loss

二元组正例和负例存在严重不平衡,选择什么的负例呢?三元组选择有多种多种,但什么样的三元组是最优的选择? 引入了二元组,三元组为了解决问题,然而又带来了新的问题。有木有什么方法可以不必纠结如何选择有效的二元组,三元组吗?当然有的。直观的想法就是用Softmax 作为损失函数训练分类的损失,用全连接层特征作为人脸特征进行相似度比较。但是,Softmax只会使类别分开,并不会约束类内距离,特征会相对稀疏散布在分界面之间,我自己做了一个实验,用Softmax训练了Mnist数据集, 设置最后一层全连接层特征为2维,可视化出现结果如图6所示。

由于Softmax损失不会对类内特征做任何约束,那么在特征空间(以特征维度为2示例)中,分界面之间的区域都会被认为是一类。在人脸识别任务下,人脸数据集很难覆盖所有人,也就说如果把单个人为一类的话,分界面之间区域特征都认为这个人是很不合理的。就会出现新的类别测试的时候,特征会落到某个类特征区域内,那么就会判断为该类,出现误判。针对这种情况,Wen [8]提出了center loss。整个训练的损失函数等于Softmax loss加上center loss。
其中center loss损失函数如下:
LC=12i=1m(xicyi)22L_C= \frac{1}{2} ∑_{i=1}^m (∥x_i-c_{y_i}∥)_2^2

CyiRdC_{yi} \in R^d表示第YiY_i 类的特征中心。Center loss目标是让每类的特征尽可能集中,让每类在特征空间内所占的范围尽可能小,测试时当新的类别出现时,不会误判为已有的类别。结合center loss和softmax loss在一起,在Mnist的结果如图6右图所示,每类所占的空间极小。新的类出现,减少了误判的可能。

A-Softmax Loss

从图6左图可以看出,使用Softmax作为分类器,在二维空间内特征分布呈现圆形,三维空间中分布呈现球形。因此,在圆形、球形的分布中,如果使用欧式距离来衡量特征之间的距离,是不合理的,基于此,作者提出了用角度距离来衡量特征之间的距离的方法A-Softmax。以二分类为例,传统的Softmax 分类器可以得到分界面:
W1Tx+b=X2Tx+b(W1TW2T)x(b1b2)=0W_1^Tx+b = X_2^Tx+b \to (W_1^T - W_2^T)x - (b_1 - b_2) = 0
可以把Softmax 写成角度的形式:
W1xcos(θ1)+b1=W2xcos(θ2)+b2 ||W_1||||x||cos(\theta_1) + b_1 = ||W_2||||x||cos(\theta_2) + b_2
将W, b进行normalize 操作以后使wi=1,bi=0||w_i||=1,b_i=0 ,分界面就变为了 x(cos(θ1)cos(θ2))=0||x||(cos(\theta_1) - cos(\theta_2)) = 0,这样就可以从角度入手学习分界面,作者将这种方法叫做Modified Softmax。在人脸任务中,还需要保证同一个人的特征尽可能近,不同的人特征尽可能远。作者在Modified Softmax基础上提出了加入超参数m来限制类内距离小于类间距离。在Modified Softmax中,如果cos(θ1)>cos(θ2)cos(\theta_1) > cos(\theta_2) 认为输入第一类,修改的A-Softmax 则是cos(mθ1)>cos(θ2)cos(m\theta_1) > cos(\theta_2)成立的时候,才被认为是第一类,满足这样条件的θ_1 范围就降低了很多,这样就缩小了类内的距离。论文中m=4。第二类同理。
修改后的A-Softmax损失函数如下所示:
Li=1Nilog(exicos(mθ(yi),i)exicos(mθyi,i)+jyiexicos(θj,i))L_i=\frac{1}{N} ∑_i-\log(\frac{ e^{∥x_i∥\cos⁡(mθ_(y_i ),i) }}{e^{∥xi∥\cos(mθyi,i)} + \sum_{j ≠yi}e^{∥xi∥\cos(θj,i)}})

Softmax,Modified Softmax, A-Softmax作用下的特征分布如图7所示:

Cosine 距离是一个非线性距离,在人脸度量上比线性的欧式距离更有优势,加入超参数m,相当于在原有角度距离的基础上,限制了类内距离,保证类间距离大的同时类内距离小。正是如此,该算法也取得了Megaface竞赛的第一名。

结语:由于本人水平有限,文中如有错误,请留言指出错误,万分感谢。

参考文献:

[1] Alex Krizhevsky, Ilya Sutskever, Geoffrey E. Hinton ImageNet Classification with Deep Convolutional Neural Networks NIPS 2012
[2] http://vis-www.cs.umass.edu/lfw/
[3] http://www.cbsr.ia.ac.cn/english/CASIA-WebFace-Database.html
[4] https://www.microsoft.com/en-us/research/project/ms-celeb-1m-challenge-recognizing-one-million-celebrities-real-world/
[5] Sumit Chopra, Raia Hadsell, Yann LeCun Learning a Similarity Metric Discriminatively, with Application to Face Verification. CVPR 2005
[6] Florian Schroff, Dmitry Kalenichenko , James Philbin. FaceNet: A Unified Embedding for Face Recognition and Clustering CVPR 2015
[7] Yandong Wen, Kaipeng Zhang, Zhifeng Li, Yu Qiao. A Discriminative Feature Learning Approach
for Deep Face Recognition ECCV 2016
[8] Weiyang Liu, Yandong Wen, Zhiding Yu, Ming Li, Bhiksha Raj, Le Song SphereFace: Deep Hypersphere Embedding for Face Recognition CVPR 2017

2016-09-07 14:15:34 qq_36075166 阅读数 1085
  • 卷积神经网络与人脸识别系统实战视频教程

    卷积神经网络与人脸识别系统实战视频培训课程概况:本教程从零开始讲解人工神经网络,卷积神经网络等基础内容,然后讲解基于python如何构建一个深度学习模型,后基于CNN,利用keras构建网络结构打造一个人脸识别系统。

    2558 人正在学习 去看看 王而川
基于深度学习架构android人脸识别[离线版]APP免费下载。

经过半年的深度闭关研发,千搜科技终于成功将深度学习架构移植到android平台。并且成功将人脸识别应用移植到了android平台。

现在怀着无比激动的心情将内测软件公布出来,分享给各位对人脸识别有兴趣的同仁,希望多多提出宝贵意见。


    
    


2019-06-09 23:30:18 wjh2622075127 阅读数 269
  • 卷积神经网络与人脸识别系统实战视频教程

    卷积神经网络与人脸识别系统实战视频培训课程概况:本教程从零开始讲解人工神经网络,卷积神经网络等基础内容,然后讲解基于python如何构建一个深度学习模型,后基于CNN,利用keras构建网络结构打造一个人脸识别系统。

    2558 人正在学习 去看看 王而川

引言

人脸识别和人脸检测不同,人脸检测时检测到人脸位置,而人脸识别是基于人脸数据库,进行一些识别操作如识别某一个人像是数据库中的哪个标签。

需要说明的是,使用knn和Dense层的神经网络作为人脸识别算法只是我的尝试,在实际的使用中基本不使用这两种算法的。同时,经过实际测试,这样得到的结果极不准确,甚至可以说毫无效果(苦笑)。


人脸数据获取

进行人脸识别首先要有人脸数据库,我们可以用opencv调用摄像头,进行人脸检测,并将人脸灰度图片写入到(200, 200)的pgm文件作为我们的人脸数据库。

code

import cv2

def generate():
    face_cascade = cv2.CascadeClassifier( # haar级联文件-人脸
        './cascades/haarcascade_frontalface_default.xml'
    )
    camera = cv2.VideoCapture(0)
    count = 0

    while True:
        ret, frame = camera.read()
        frame = cv2.flip(frame, 1)  # 翻转为正常角度
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #转灰度处理
        faces = face_cascade.detectMultiScale(gray, 1.3, 5) # 识别

        for (x, y, w, h) in faces:
            img = cv2.rectangle( # 画框图
                frame, (x, y), (x + w, y + h), (255, 0, 0), 2
            )
            # cv2.putText(
            #     img, 'name', (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2
            # )
            f = cv2.resize(gray[y: y+h, x: x+w], (200, 200)) # 统一大小
            cv2.imwrite('./data/at/name/%s.pgm' % str(count), f) # 将人脸数据写入到pgm文件中
            count += 1
        if count == 200:
            break

        cv2.imshow('camera', frame)
        if cv2.waitKey(int(1000 / 12)) & 0xff == ord("q"): # 等待q键
            break

    camera.release()
    cv2.destroyAllWindows()
    return

if __name__ == '__main__':
    generate()

处理图片读取到并数组中

这个代码是读取数据的模块,在后面的代码中多次调用以获取数据
将上一步存储的图片数据转化为可处理的numpy数组,提供了两种相似的接口函数。

read_images 为普通的读取到灰度的pgm图片返回的数组
read_images_binary 是将pgm图片进行了二值化处理得到的数组数据

返回的数据类型为 list, list, dict
分别为 图片数据、图片标签、标签和人名的映射字典

import os, sys, re
import cv2
import numpy as np

def read_images(path, sz=None): # 读取自己的图片数据库
    c = 0
    X, y = [], []
    dic = {}
    for dirname, dirnames, filenames in os.walk(path): # 遍历文件夹下文件
        for subdirname in dirnames:
            subject_path = os.path.join(dirname, subdirname)
            # print("subdirname = ", dirname)
            # print("subject_path = ", subject_path)
            for filename in os.listdir(subject_path):
                if filename[-4:] != '.pgm': # 如果文件不是pgm文件,那么跳过
                    continue
                filepath = os.path.join(subject_path, filename) # 生成完整的文件名
                # print(filepath)
                im = cv2.imread(os.path.join(subject_path, filename), \
                                cv2.IMREAD_GRAYSCALE) # 读取pgm图片
                # print(np.shape(im))
                # 改变大小
                if sz is not None:
                    im = cv2.resize(im, (200, 200)) # 调整图片大小

                X.append(np.asarray(im, dtype=np.uint8))
                y.append(c)
            # print(re.findall(r'./data/at/(.*)', subject_path))
            dic[c] = re.findall(r'./data/at/(.*)', subject_path)[0]
            c = c + 1
    # print("c = ", c)
    # print(X)
    return [X, y], dic

def read_images_binary(path, sz=None): # 读取自己的图片数据库
    c = 0
    X, y = [], []
    dic = {}
    for dirname, dirnames, filenames in os.walk(path): # 遍历文件夹下文件
        for subdirname in dirnames:
            subject_path = os.path.join(dirname, subdirname)
            # print("subdirname = ", dirname)
            # print("subject_path = ", subject_path)
            for filename in os.listdir(subject_path):
                if filename[-4:] != '.pgm': # 如果文件不是pgm文件,那么跳过
                    continue
                filepath = os.path.join(subject_path, filename) # 生成完整的文件名
                # print(filepath)
                im = cv2.imread(os.path.join(subject_path, filename), \
                                cv2.IMREAD_GRAYSCALE) # 读取pgm图片
                ret, im = cv2.threshold(im, 120, 255, cv2.THRESH_BINARY)
                if sz is not None:
                    im = cv2.resize(im, (200, 200)) # 调整图片大小

                X.append(np.asarray(im, dtype=np.uint8))
                y.append(c)
            # print(re.findall(r'./data/at/(.*)', subject_path))
            dic[c] = re.findall(r'./data/at/(.*)', subject_path)[0]
            c = c + 1
    # print("c = ", c)
    # print(X)
    return [X, y], dic

调用opencv内置函数进行人脸识别

内置的三种人脸识别函数

model = cv2.face.EigenFaceRecognizer_create() # 这个版本的opencv名字改了,和书上的有点不一样
model = cv2.face.LBPHFaceRecognizer_create(1, 8, 8, 90)
model = cv2.face.FisherFaceRecognizer_create()

调用opencv-python提供的这三种人脸识别函数,发现效果都不好。人脸总是检测错误,准确率极低,要它何用?(不知道是不是我使用姿势不太正确)于是我催生出自己实现人脸识别算法那的念头。

观察框出的人脸,觉得一个人的人脸图片,单单框出了人脸,那应该相似度很高啊。类似于手写数字识别,简单的knn算法可以达到很高的正确率,那么是不是可以用knn较好的解决这个问题。

实践出来的结果是:不是的。

code

import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
from getData import read_images

def cv2ImgAddText(img, text, left, top, textColor=(0, 255, 0), textSize=20):
    img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img)
    fontText = ImageFont.truetype(
        "SimHei.ttf", textSize, encoding="utf-8")
    draw.text((left, top), text, textColor, font=fontText)
    return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)

def face_rec(): # 人脸识别

    [X, y], label2name = read_images('./data/at')
    print("label2name:", label2name)
    print(np.shape(X))
    print("label2name = ", label2name)
    print(np.shape(X))
    # print("y = ", y)
    y = np.asarray(y, dtype=np.int32)

    # 调用人脸识别函数生成模型
    # model = cv2.face.EigenFaceRecognizer_create() # 这个版本的opencv名字改了,和书上的有点不一样
    model = cv2.face.LBPHFaceRecognizer_create(1, 3, 8, 8)
    model.train(np.asarray(X), np.asarray(y)) # 训练
    camera = cv2.VideoCapture(0)
    face_cascade = cv2.CascadeClassifier( # 分类器检测人脸
        './cascades/haarcascade_frontalface_default.xml'
    )
    while True:
        read, img = camera.read()
        img = cv2.flip(img, 1)  # 翻转为正常角度
        faces = face_cascade.detectMultiScale(img, 1.3, 5)
        for (x, y, w, h) in faces:
            img = cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            roi = gray[x: x+2, y: y+h]
            roi = cv2.resize(roi, (200, 200), interpolation=cv2.INTER_LINEAR)
            params = model.predict(roi) # 预测
            print(params) # 返回 (图片标签, 置信度)
            if params[0] >= 0:
                name = label2name[params[0]]
            else:
                name = "未知"
            print("检测到%s" % name)
            print("label: %s, Confidence: %.2f" % (params[0], params[1]))
            img = cv2ImgAddText(img, name, x, y - 20, (255, 255, 0), 20)
            # cv2.putText(img, name, (x, y - 20),
            #             cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2) # putText只能写上ascii中的部分字符, 呵呵
        # print(img)

        cv2.imshow('camera', img)
        if cv2.waitKey(1000 // 12) & 0xff == ord("q"):
            break
    cv2.destroyAllWindows()

if __name__ == "__main__":
    face_rec() # 人脸识别

knn算法进行人脸识别

简单的knn模板

knn 实现

import numpy as np
import matplotlib.pyplot as plt
from getData import read_images

def knn(xtest, data, label, k): # xtest为测试的特征向量,data、label为“训练”数据集,k为设定的阈值
#     print(xtest.shape)
#     print(label.shape)
    exp_xtest = np.tile(xtest, (len(label), 1)) - data
    sq_diff = exp_xtest**2
    sum_diff = sq_diff.sum(axis=1)
    distance = sum_diff**0.5
    # print(distance)
    sort_index = distance.argsort()
    classCount = {}
    for i in range(k):
        one_label = label[sort_index[i]]
        classCount[one_label] = classCount.get(one_label, 0) + 1
    sortedClassCount = sorted(classCount.items(), key = lambda x:x[1], reverse=True)
    print(distance.sum())
    print(classCount)
    print(sortedClassCount)
    return sortedClassCount[0][0]

def main():
    [X, y], label2name = read_images('./data/at/')
    print(np.shape(X))
    X = np.array(X)
    Xx = X.reshape(X.shape[0], 40000)
    xdata, label = Xx, y
    result = knn(np.array(xdata[67]), xdata, label, 3)
    print("result = ", label2name[result])
    return result

if __name__ == '__main__':
    main()

调用knn的主体部分

import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
from getData import read_images_binary
from knn import knn


def cv2ImgAddText(img, text, left, top, textColor=(0, 255, 0), textSize=20):
    img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img)
    fontText = ImageFont.truetype(
        "SimHei.ttf", textSize, encoding="utf-8")
    draw.text((left, top), text, textColor, font=fontText)
    return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)

def face_rec(): # 人脸识别

    [X, y], label2name = read_images_binary('./data/at')
    X = np.array(X)
    Xx = X.reshape(X.shape[0], 40000)
    xdata, label = Xx, y

    y = np.asarray(y, dtype=np.int32)
    face_cascade = cv2.CascadeClassifier( # 分类器检测人脸
        './cascades/haarcascade_frontalface_default.xml'
    )
    videoCapture = cv2.VideoCapture(0)
    while True:
        read, img = videoCapture.read()
        img = cv2.flip(img, 1)
        faces = face_cascade.detectMultiScale(img, 1.3, 5)
        for (x, y, w, h) in faces:
            img = cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            roi = gray[x: x+2, y: y+h]
            roi = cv2.resize(roi, (200, 200), interpolation=cv2.INTER_LINEAR)
            roi = np.array(roi).reshape(40000, )
            result = knn(roi, xdata, label, 3)
            print(result) # 返回结果的标签
            name = label2name[result]
            print("检测到%s" % name)
            img = cv2ImgAddText(img, name, x, y - 20, (255, 255, 0), 20)
        cv2.imshow('camera', img)
        if cv2.waitKey(1000 // 12) & 0xff == ord("q"):
            break
    cv2.destroyAllWindows()

if __name__ == "__main__":
    face_rec() # 人脸识别

使用Dense层神经网络进行人脸识别

简单的神经网络多分类器实现(效果不好,大概是数据太少,每个人只有200张(200, 200) 的pgm图片数据。

调用keras的高级API,搭积木一样的建立神经网络。

即使是这么少的数据,训练一次的时间也要好几分钟。调参调了好久,关键是调不出效果啊~

from getData import read_images, read_images_binary
import numpy as np
from tensorflow.keras import models
from tensorflow.keras import layers

def to_onehot(y): # 将标签转化为独热码oen-hot
    print("max of y = ", np.max(y))
    onehots = np.zeros((len(y), np.max(y) + 1), dtype=np.float)
    for i in range(len(y)):
        onehots[i][y[i]] = 1.0
    print("shape of onehots : ", np.shape(onehots))
    return onehots

def get_model_dense(size=(200, 200)): # 设置一个全连接层网络,返回模型,未训练
    model = models.Sequential([
        layers.Dense(16, activation='relu', input_shape=((40000, ))),
        layers.Dense(16, activation='relu'),
        layers.Dense(16, activation='relu'),
        layers.Dense(4, activation='softmax')
    ])
    model.compile(
        optimizer='rmsprop',
        loss='categorical_crossentropy',
        metrics=['accuracy']
    )
    return model

def k_fold_validation(train_data, train_targets):
    k = 4
    num_val_samples = len(train_data) // k
    num_epochs = 5
    all_scores = []

    for i in range(k):
        print('processing fole # ', i)
        val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples]
        val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples]

        partial_train_data = np.concatenate(
            [train_data[:i * num_val_samples],
            train_data[(i + 1) * num_val_samples:]],
            axis=0
        )
        partial_train_targets = np.concatenate(
            [train_targets[:i * num_val_samples],
             train_targets[(i + 1) * num_val_samples:]],
            axis = 0
        )
        model = get_model_dense()
        model.fit(
            partial_train_data,
            partial_train_targets,
            epochs=num_epochs,
            batch_size=3
        )
        '''
        model5开始,对图片进行了阈值为120的图片二值化处理
        model6调整了参数(防止过拟合),从64调成16
        model7加了一层
        '''
        model.save('dense_model_7.h5')
        val_mse, val_mae = model.evaluate(val_data, val_targets)
        all_scores.append(val_mae)

def main():
    [X, y], label2name = read_images_binary('./data/at/') # 调用人脸数据
    X = np.array(X).reshape(len(X), 40000) / 255
    y = to_onehot(np.array(y))
    index = np.arange(len(X))
    np.random.shuffle(index) # 生成打乱的索引
    print("index = ", index)
    X = X[index] # 得到打乱的数据
    y = y[index]
    print(X)
    print(y)
    print(X.shape)
    print(y.shape)
    k_fold_validation(X, y)


if __name__ == "__main__":
    main()

主体部分

import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
from getData import read_images
from knn import knn
from tensorflow.keras import models


def cv2ImgAddText(img, text, left, top, textColor=(0, 255, 0), textSize=20):
    img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img)
    fontText = ImageFont.truetype(
        "SimHei.ttf", textSize, encoding="utf-8")
    draw.text((left, top), text, textColor, font=fontText)
    return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)

def face_rec(): # 人脸识别

    [X, y], label2name = read_images('./data/at')
    print("label2name: ", label2name)
    X = np.array(X)
    Xx = X.reshape(X.shape[0], 40000)
    xdata, label = Xx, y

    y = np.asarray(y, dtype=np.int32)
    face_cascade = cv2.CascadeClassifier( # 分类器检测人脸
        './cascades/haarcascade_frontalface_default.xml'
    )
    videoCapture = cv2.VideoCapture(0)

    model = models.load_model('dense_model_6.h5')

    while True:
        read, img = videoCapture.read()
        img = cv2.flip(img, 1)
        faces = face_cascade.detectMultiScale(img, 1.3, 5)
        for (x, y, w, h) in faces:
            img = cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            roi = gray[x: x+2, y: y+h]
            roi = cv2.resize(roi, (200, 200), interpolation=cv2.INTER_LINEAR)
            roi = np.array(roi).reshape(40000, )
            prediction = model.predict(np.array([roi]))
            # print(np.shape(roi))
            print("dnn predict result :", prediction)
            index = np.argmax(prediction) # 最大值所在的索引
            name = label2name[index]
            print("检测到%s" % name)
            img = cv2ImgAddText(img, name, x, y - 20, (255, 255, 0), 20)
        cv2.imshow('camera', img)
        if cv2.waitKey(1000 // 12) & 0xff == ord("q"):
            break
    cv2.destroyAllWindows()

if __name__ == "__main__":
    face_rec() # 人脸识别

一些小知识点

opencv putText无法写中文

putText()不能直接写上中文,那就用PIL库曲线救国了。下面是一个demo。

#coding=utf-8
#中文乱码处理

import cv2
import numpy
from PIL import Image, ImageDraw, ImageFont

def cv2ImgAddText(img, text, left, top, textColor=(0, 255, 0), textSize=20):
    img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img)
    fontText = ImageFont.truetype(
        "SimHei.ttf", textSize, encoding="utf-8")
    draw.text((left, top), text, textColor, font=fontText)
    return cv2.cvtColor(numpy.asarray(img), cv2.COLOR_RGB2BGR)

img = cv2.imread('./test.png')
img = cv2ImgAddText(img, "你好世界", 140, 60, (255, 255, 0), 20)
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

二值化图片

使用cv2.threshold()函数,设置cv2.THRESH_BINARY参数进行二值化。可以设置阈值。

import cv2
import numpy as np

img = cv2.imread('test.jpg')
# img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite('test.jpg', cv2.Canny(img, 50, 120))
cv2.imshow('canny', cv2.imread('test.jpg'))
ret, img = cv2.threshold(img, 110, 255, cv2.THRESH_BINARY)
cv2.imshow('binary', img)
cv2.waitKey()
cv2.destroyAllWindows()

路径目录测试

由于代码文件和图片文件中间隔了两个文件夹,且图片所在文件夹名称代表图片标签名称,所以如何遍历文件夹,读取到有用的信息是个技术活。

import os

path = './data'
for dirname, dirnames, filenames in os.walk(path):
    for subdirname in dirnames:
        subject_path = os.path.join(dirname, subdirname)
        # print(subject_path)
        for filename in os.listdir(subject_path):
            if filename[-4:] == '.pgm':
                filepath = os.path.join(subject_path, filename)
                print(filepath)

np.random.shuffle() 测试

np.random.shuffle() 能够将某一迭代对象进行打乱。
会直接改变传递给他的对象,而不会返回值,需要注意。

用这个函数,生成索引的随机排列,可以很方便的得到打乱的数据和标签,从而更好的进行训练。

import numpy as np

a = range(0, 10)
print(a)
print(type(a[9]))
print(np.array(a))
index = np.array(a)
np.random.shuffle(index)
print(index)

index = np.arange(7)
print(index)

keras保存和恢复模型

from tensorflow.keras import models
model.save('dense_model_7.h5')
model = models.load_model('dense_model_6.h5')
就不用每次都重新训练了。

2019-05-09 09:09:51 whale52hertz 阅读数 111
  • 卷积神经网络与人脸识别系统实战视频教程

    卷积神经网络与人脸识别系统实战视频培训课程概况:本教程从零开始讲解人工神经网络,卷积神经网络等基础内容,然后讲解基于python如何构建一个深度学习模型,后基于CNN,利用keras构建网络结构打造一个人脸识别系统。

    2558 人正在学习 去看看 王而川

文章来源:ATYUN AI平台 

松下公司宣布,采用深度学习技术的人脸识别服务器软件将于2018年7月在海外先行推出,而8月才在日本本土推出。

[视频]使用深度学习技术的人脸识别服务器软件

视频链接:松下推出人脸识别服务器软件 使用深度学习技术

拥有世界上最佳的人脸识别性能的特色核心引擎,这种高精度的人脸识别软件可以识别传统技术难以识别的人脸,包括脸部角度为向左或向右45度、向上或向下30度和部分隐藏的太阳镜的人脸。

此外,新软件的特点是“iA(智能自动)模式”,新软件可以自动调整相机的设置,找到最适合拍摄人脸的角度。当它与松下的i-PRO EXTREME系列网络相机一起使用时,安装了与软件捆绑的“最佳拍摄许可密钥”,只有“最佳镜头”将被发送到服务器进行人脸识别。松下核心设备与人脸识别软件的结合,最大限度地提高了软件核心引擎的性能,实现了高精度的识别。该公司计划在今年年底前增加一项功能,以识别部分蒙着口罩的脸,这在传统的系统中是很困难的。

此外,使用带有iA功能的摄像头,可以在摄像头上进行图像分析,不需要将图像发送到服器。这将导致减少服务器和网络负载,从而降低整个系统的成本。在系统连接10个或更多的网络摄像头的情况下,与不使用最佳拍摄功能的传统系统相比,成本可以降低约40 – 50%。

松下将继续改进相关产品,并提供各种解决方案,以满足日益多样化和不断发展的客户需求,如用于与监控系统进行集成管理的人脸识别解决方案。通过提供这些解决方案,公司致力于成为能够为客户的前线业务做出贡献的“全面整合者(total integrator)”。

松下的深度学习人脸识别软件具有以下特点:

1.精度高:

-由NIST(IJB-A face challenge,是美国最权威的研究机构之一)评估的世界上精度最高的人脸识别引擎;

– iA功能和最佳拍摄图像最大限度的提高人脸识别引擎性能和识别精度。

2.系统成本降低:只发送“最佳拍摄”图像,以减少服务器负载和网络负载。

3.系统可扩展性:

-最多注册30,000张人脸;

-用i-PRO监控系统进行集成管理:通过相同的GUI实现人脸识别系统和监控系统的集成管理。

 

松下推出人脸识别服务器软件 使用深度学习技术

 

[发展背景]

随着物联网和人工智能的快速普及,连接各种信息以使生活更加便利的举措正在每个工业部门进行。为了实现这一目标,一种名为“深度学习”的新技术得到应用。松下在面向安全行业的人脸识别产品中采用了这种深度学习技术。使得人脸识别技术成功开发并且商业化,该技术克服了传统技术的难题,例如脸部倾斜,由于衰老而变化的脸部或因为戴了太阳镜而隐藏部分脸部。松下将提供此产品作为视频安全性的个人识别解决方案,用于各种情况下,如公共设施监控和入门管理。

[产品特点]

1.精度高:
– 由NIST评估的顶级人脸识别引擎(IJB-A面临的挑战);

– 新软件中使用的深度学习技术与新加坡国立大学联合开发,与传统系统相比,可将人脸识别性能提高达500%;

– 一种结合深度学习的独特算法,与一种抑制错误的相似度计算方法相结合,可以在常规人脸识别技术难以实现的情况下进行识别,例如当脸部倾斜(脸部角度为向左或向右45度、向上或向下30度),由于太阳镜或口罩隐藏部分脸部,或因衰老而改变;

– iA功能和最佳拍摄图像可最大限度地提高人脸识别引擎的性能并提供高识别精度;

– iA功能使相机能够自动检测场景并相应地自动优化设置,以提高视频图像的可检测性。相机会自动检测视频中的移动物体,移动速度,脸部和光线强度(白天/夜晚/头灯),并实时优化设置并获得更佳效果主题的视频;

– 此软件附带的最佳拍摄许可证密钥可以安装在Panasonic i-PRO EXTREME系列网络摄像机上,以便从摄像机前拍摄的多张人脸图像中自动选择适合人脸识别的图像,并只将这些选定的图像发送到服务器。这使得高质量的图像能够在无需加载服务器负载的情况下被发送。

2.系统成本降低:
– 只发送最佳拍摄图像以减少服务器负载和网络负载;

– 使用传统的人脸识别系统时,所有捕获的图像都会发送到服务器,由服务器执行人脸检测和人脸识别,从而将数据处理的负担集中在服务器上。由于发送所有图像所需的大带宽以及保存这些图像所需的高容量硬盘空间,系统也往往是大规模的。

– 将本产品与包含iA功能的相机结合使用的松下系统允许相机检测人脸,并且只有包含脸部的最佳拍摄图像才能发送到服务器,从而显着降低网络负载并消除大型化带宽。使用最佳镜头图像在服务器上执行人脸识别可降低服务器负载和硬盘驱动器容量要求,并允许将多达20 * 5个网络摄像头连接到单台服务器。

– 与传统系统不同,使用该Panasonic系统,不再需要将数据密集型高分辨率图像发送到服务器。该系统可以提供高精度的人脸识别,同时显着降低网络流量,传输成本和网络建设成本。

– 使用连接10台或更多网络摄像机的松下系统时,与不使用最佳拍摄功能的传统系统相比,其成本可降低约40%至50%。

3.系统可扩展性:
– 最多注册30,000张人脸;

– 使用标准人脸识别服务器软件(WV-ASF950),可以对最多10,000张人脸进行简单的批量注册。人脸注册扩展套件(WV-ASFE951W)可在大型设施中注册多达30,000张人脸。

– 使用i-PRO监控系统进行集成管理,通过使用Panasonic i-PRO监视系统的WV-ASM300或WV-ASE231W客户端软件进行集成管理,可以在同一GUI中执行录制视频的人脸检测,人脸识别和跟踪。这消除了传统人脸识别系统所需的专用操作和管理,使得工作可以集中。

本文转自ATYUN 人工智能媒体平台,原文链接:松下推出人脸识别服务器软件 使用深度学习技术

更多推荐

伯克利人工智能研究项目:为图像自动添加准确的说明

Deep Photo Styletransfer的一种纯Tensorflow实现,教你如何转换图片风格

将Keras权值保存为动画视频,更好地了解模型是如何学习的

DeepMind认为:神经科学与人工智能的联手已无法阻挡!

欢迎关注ATYUN官方公众号,商务合作及内容投稿请联系邮箱:bd@atyun.com
欢迎关注ATYUN官方公众号,商务合作及内容投稿请联系邮箱:bd@atyun.com

 

2018-08-24 21:39:35 fendouaini 阅读数 1796
  • 卷积神经网络与人脸识别系统实战视频教程

    卷积神经网络与人脸识别系统实战视频培训课程概况:本教程从零开始讲解人工神经网络,卷积神经网络等基础内容,然后讲解基于python如何构建一个深度学习模型,后基于CNN,利用keras构建网络结构打造一个人脸识别系统。

    2558 人正在学习 去看看 王而川

作者 | 东田应子

【磐创AI导读】本文是深度学习之视频人脸识别系列的第二篇文章,介绍人脸检测与对齐的相关算法。欢迎大家关注我们的公众号:磐创AI。

一、人脸检测与关键点检测

  1. 问题描述:

人脸检测解决的问题为给定一张图片,输出图片中人脸的位置,即使用方框框住人脸,输出方框的左上角坐标和右下角坐标或者左上角坐标和长宽。算法难点包括:人脸大小差异、人脸遮挡、图片模糊、角度与姿态差异、表情差异等。而关键检测则是输出人脸关键点的坐标,如左眼(x1,y1)、右眼(x2,y2)、鼻子(x3,y3)、嘴巴左上角(x4,y4)、嘴巴右上角(x5,y5)等。

  1. 深度学习相关算法:

(1)Cascade CNN

Cascade CNN源于发表于2015年CVPR上的一篇论文A Convolutional Neural Network Cascade for Face Detection【2】,作者提出了一种级连的CNN网络结构用于人脸检测。算法主体框架是基于V-J的瀑布流思想【1】,是传统技术和深度网络相结合的一个代表,Cascade CNN包含了多个分类器,这些分类器使用级联结构进行组织,与V-J不同的地方在于Cascade CNN采用卷积网络作为每一级的分类器。整个网络的处理流程如下图所示:

这里写图片描述

整个处理流程里包含了六个网络:12-net、12-calibration-net、24-net、24-calibration-net、48-net、48-calibration-net,其中三个二分类网络用于分类其是否为人脸,另外三个calibration网络用于矫正人脸框边界。其中第二个网络之后、第四个网络之后、第五个网络之后使用NMS算法过滤掉冗余的框。

12-net,24-net和48-net的网络结构如下图所示:

这里写图片描述

13-12-calibration-net,24-calibration-net,48-calibration-net的结构如下图所示:

这里写图片描述

该算法结合了V-J框架构造了级连的CNN网络结构并设计边界矫正网络用来专门矫正人脸框边界,在AFW数据集上准确率达到97.97%。

这里写图片描述

(2)Faceness-Net

Faceness-Net源于论文A convolutional neural network cascade for face detection【3】,该算法基于DCNN网络【5】的人脸局部特征分类器,算法首先进行人脸局部特征的检测,使用多个基于DCNN网络的facial parts分类器对人脸进行评估,然后根据每个部件的得分进行规则分析得到Proposal的人脸区域,然后从局部到整体得到人脸候选区域,再对人脸候选区域进行人脸识别和矩形框坐标回归,该过程分为两个步骤。

第一个步骤:每个人脸局部特征使用attribute-aware网络检测并生成人脸局部图,其中一共五个特征属性: 头发、眼睛、鼻子、嘴巴、胡子。然后通过人脸局部图根据评分构建人脸候选区域,具体如下图所示:

这里写图片描述

第二个步骤:训练一个多任务的卷积网络来完成人脸二分类和矩形框坐标回归,进一步提升其效果,具体如下图所示:

这里写图片描述

Faceness从脸部特征的角度来解决人脸检测中的遮挡和姿态角度问题,其整体性能在当时是非常好的,在AFW数据集上准确率可以达到98.05%。
这里写图片描述

(3)MTCNN

MTCNN源于论文Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks【6】,是基于多任务级联卷积神经网络来解决人脸检测和对齐问题,同时输出图片的人脸矩阵框和关键点坐标(左眼、右眼、鼻子、嘴巴左上角、嘴巴右上角)。MTCNN为三阶的级联卷积神经网络,整体框架如下图所示:
这里写图片描述

输入阶段:为应对目标多尺度问题,将原始图像resize到不同尺寸,构建图像金字塔,作为三阶级联架构的输入,这样处理可以更好地检测大小不一的人脸。

第一阶段:通过一个全部由卷积层组成的CNN,取名P-Net,获取候选人脸框、关键点坐标和人脸分类(是人脸或不是),之后采用NMS过滤掉高重叠率的候选窗口。如下图所示:

这里写图片描述

第二阶段:第一阶段输出的候选人脸框作为更为复杂的R-Net网络的输入,R-Net进一步筛除大量错误的候选人脸框,同样也通过NMS过滤掉高重叠率的候选窗口。如下图所示:

这里写图片描述

第三阶段:与第二阶段类似,最终网络输出人脸框坐标、关键点坐标和人脸分类(是人脸或不是)。如下图所示:

这里写图片描述

MTCNN通过三级的级联卷积神经网络对任务进行从粗到细的处理,还提出在线困难样本生成策略(online hard sample mining )可以进一步提升性能。兼并了速度与准确率,速度在GPU上可以达到99FPS,在 FDDB数据集上可以达到95.04准确率,具体如下图所示:

这里写图片描述

二、人脸对齐(部分参考于GraceDD的博客文章)

人脸对齐通过人脸关键点检测得到人脸的关键点坐标,然后根据人脸的关键点坐标调整人脸的角度,使人脸对齐,由于输入图像的尺寸是大小不一的,人脸区域大小也不相同,角度不一样,所以要通过坐标变换,对人脸图像进行归一化操作。人脸关键点检测有很多算法可以使用包括:ASM、AAM、DCNN 、TCDCN 、MTCNN 、TCNN、TCNN等,这里就不详细介绍,主要说一下得到人脸关键点之后如何进行人脸对齐,是所有人脸达到归一化效果,该过程如下图所示:

这里写图片描述

该过程涉及到图像的仿射变换,简单来说,“仿射变换”就是:“线性变换”+“平移”,即坐标的变换。假如我们希望人脸图片归一化为尺寸大小600*600,左眼位置在(180,200),右眼位置在(420,200)。 这样人脸中心在图像高度的1/3位置,并且两个眼睛保持水平,所以我们选择左眼角位置为( 0.3*width, height / 3 ),右眼角位置为(0.7*width , height / 3) 。

利用这两个点计算图像的变换矩阵(similarity transform),该矩阵是一个2*3的矩阵,如下:

这里写图片描述

如果我们想对一个矩形进行变换,其中x、y方向的缩放因为分别为sx,sy,同时旋转一个角度 ,然后再在x方向平移tx, 在y方向平移ty

利用opencv的estimateRigidTransform方法,可以获得这样的变换矩阵,但遗憾的是,estimateRigidTransform至少需要三个点,所以我们需要构选第三个点,构造方法是用第三个点与已有的两个点构成等边三角形,这样第三个点的坐标为:

这里写图片描述

代码如下:

这里写图片描述

经过上一步的处理之后,所有的图像都变成一样大小,并且又三个关键点的位置是保持一致的,但因为除了三个点对齐了之外,其他点并没有对齐。所以根据得到的变换矩阵对剩下所有的点进行仿射变换,opencv代码如下所示:

这里写图片描述

img为输入图像;

warped为变换后图像,类型与src一致;

M为变换矩阵,需要通过其它函数获得,当然也可以手动输入;

Image_size为输出图像的大小;

三、 总结

本期文章主要介绍了人脸检测与对齐的相关算法,下一期我给大家介绍一下人脸表征的相关算法,即通过深度学习提取人脸特征,通过比较人脸特征进行人脸识别与验证。

参考文献:

【1】 S.Z.Li, L.Zhu, Z.Q.Zhang, A.Blake, H.J.Zhang, H.Y.Shum. Statistical learning of multi-view face detection. In: Proceedings of the 7-th European Conference on Computer Vision. Copenhagen, Denmark: Springer, 2002.67-81.

【2】Li H, Lin Z, Shen X, et al. A convolutional neural network cascade for face detection[C]//Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2015: 5325-5334.

【3】Yang S, Luo P, Loy C C, et al. Faceness-Net: Face detection through deep facial part responses[J]. IEEE transactions on pattern analysis and machine intelligence, 2017.

【4】Yang S, Luo P, Loy C C, et al. From facial parts responses to face detection: A deep learning approach[C]//Proceedings of the IEEE International Conference on Computer Vision. 2015: 3676-3684.

【5】Sun Y, Wang X, Tang X. Deep convolutional network cascade for facial point detection[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2013: 3476-3483.

【6】Zhang K, Zhang Z, Li Z, et al. Joint face detection and alignment using multitask cascaded convolutional networks[J]. IEEE Signal Processing Letters, 2016, 23(10): 1499-1503.

facenet 人脸识别

阅读数 18

没有更多推荐了,返回首页