精华内容
下载资源
问答
  • y): ''' 对人脸图片进行平移操作(向右移25像素,向上移15像素),返回新图片数据 :param image: 需要平移图片路径 :param offset_x: x坐标平移量(正 -- 向向右, 负 -- 表示向左) :param offset_y: y坐标平...

    简单的人脸识别项目

    附上我的思维导图
    在这里插入图片描述
    附上我的项目路径
    在这里插入图片描述
    其中我的lfw-a的图片库是在网上下载的
    下载网站http://vis-www.cs.umass.edu/lfw/

    下面的这个就是界面
    在这里插入图片描述
    renl

    人脸识别会对数据库进行扫描,让后加载到模型中去,到摄像头就会根据人脸进行识别显示,并打印出照片上的名字

    对数据库进行删除和查询
    在这里插入图片描述
    可以扫描你输入的目录
    在这里插入图片描述

    1. 构建数据库(使用sqlite3)

    import sqlite3
    
    FACE_SQL_NAME = "face.db"
    
    SQL_CREATE_TABLE = \
        '''
        CREATE TABLE FACE_INFO(
            ID integer PRIMARY KEY autoincrement    NOT NULL,
            NAME           TEXT    NOT NULL,
            IMAGE_PATH     TEXT
        );'''
    
    SQL_INSERT_DATA = [
        "INSERT INTO FACE_INFO (ID,NAME,IMAGE_PATH) VALUES (1, 'Paul',null )",
        "INSERT INTO FACE_INFO (ID,NAME,IMAGE_PATH) VALUES (2, 'Allen',null )",
        "INSERT INTO FACE_INFO (ID,NAME,IMAGE_PATH) VALUES (3, 'Teddy',null )",
        "INSERT INTO FACE_INFO (ID,NAME,IMAGE_PATH) VALUES (4, 'Mark',null )"
    ]
    
    SQL_QUERY_DATA = "SELECT id, name FROM FACE_INFO"
    
    SQL_UPDATE_DATA = "UPDATE FACE_INFO set IMAGE_PATH = null where ID=1"
    
    SQL_DELETE_DATA = "DELETE from FACE_INFO where ID=2;"
    
    
    def create_sqlite3(sql_name):
        '''
        根据数据库名字 创造 或者 连接 数据库
        :param sql_name:要创造或者连接的数据库名
        :return:conn 返回的是这个数据库的对象
        '''
        conn = sqlite3.connect(sql_name)
        return conn
    
    
    def sqlite_exec_sql(conn, sql):
        '''
        执行指定的SQL语句
        :param conn: 数据库的对象(他是哪个数据库)
        :param sql: 需要执行的语句时什么
        :return: cursor 返回受影响的行数
        '''
        # cursor用来执行命令的方法
        c = conn.cursor()
        # 执行单条sql语句,接收的参数为sql语句本身和使用的参数列表,返回值为受影响的行数
        cursor = c.execute(sql)
        return cursor
    
    
    def create_table(conn, sql):
        '''
        向 该数据库创建一个表
        :param conn: 需要操作的表
        :param sql: 需要执行的语句
        :return: 创建成功返回true, 失败返回false
        '''
        sqlite_exec_sql(conn, sql)
        return True
    

    2. 构建图片相关操作的函数(img_op.py)

    import numpy as np
    import os
    import cv2
    
    PATH1 = "./dog.jpg"
    PATH2 = "C:/Users/yl177/Pictures/Camera Roll/4b91f4e8f3f658aeb78dd35c79e4c3bc.jpg"
    
    
    img_file = list()
    def load_face_image_data(path):
        '''
        通过指定路径,获得该图片,将其转化为数据
        :param path: 文件路径
        :return: 图片的数据
        '''
        img_data = cv2.imread(path)
        return img_data
    
    
    def move_face_image(image_path, offset_x, offset_y):
        '''
        对人脸图片进行平移操作(向右移25像素,向上移15像素),返回新图片的数据
        :param image: 需要平移的图片路径
        :param offset_x: x坐标平移的量(正 -- 向向右, 负 -- 表示向左)
        :param offset_y: y坐标平移的量 (正 -- 向向下, 负 -- 表示向上)
        :return:
        '''
        img = load_face_image_data(image_path)
        rows = img.shape[0]
        cols = img.shape[1]
        M = np.float32([[1, 0, offset_x], [0, 1, offset_y]])
        image_new_data = cv2.warpAffine(img, M, dsize=(cols, rows))
        print(image_new_data)
        return image_new_data
    
    
    def scan_dir(path):
        '''
        扫描指定路径下的目录
        :param path:
        :return:
        '''
        if os.path.isfile(path):
            return
        file_list = os.listdir(path)
        # print(file_list)
        for item in file_list:
            temp_path = os.path.join(path, item)
            # print(temp_path)
            if os.path.isfile(temp_path):
                if temp_path.endswith("jpg") or temp_path.endswith("png"):
                    img_file.append(temp_path)
                    continue
            if os.path.isdir(temp_path):
                scan_dir(temp_path)
    
    
    def show_image(img):
        cv2.imshow('show_img', img)
        cv2.waitKey(0)
        # cv2.destroyAllWindows()
    
    
    if __name__ == '__main__':
        # old_img = load_face_image_data(PATH2)
        # new_img = move_face_image(PATH, 15, -15)
        # show_image(old_img)
        # show_image(new_img)
        scan_dir("./")
        # print(img_file)
        # print(img_file[0])
        # img = load_face_image_data(img_file[1])
        # show_image(img)
    
    
    

    3. 构建人脸相关操作(face_op.py)

    import sqlite3
    import sql as sql_op
    import img_op
    
    def sql_con():
        '''
        建立数据库的连接
        :return: 返回给数据库的对象
        '''
        return sql_op.create_sqlite3(sql_op.FACE_SQL_NAME)
    
    def face_query(conn, face_name):
        '''
        根据姓名查询此人的人脸图片
        :param conn: 该数据库的对象
        :param face_name:需要查询的人名
        :return: cursor:返回的是收到影响的行
        '''
        sql = "select ID,NAME,IMAGE_PATH from FACE_INFO where NAME='" + face_name + "'"
        cursor = sql_op.sqlite_exec_sql(conn, sql)
        return cursor
    
    def face_query_by_id(conn, id):
        '''
        根据id查询此人相关信息
        :param coon: 需要连接的数据库名
        :param id: 需要查询的id
        :return:  查到数据返回cursor,受影响的哪一行
        '''
        sql = "select ID,NAME,IMAGE_PATH from FACE_INFO where ID='" +str(id) + "'"
        cursor = sql_op.sqlite_exec_sql(conn, sql)
        return cursor
    
    def face_query_all(conn):
        '''
        查询所有数据库
        :param conn:需要连接数据库的对象
        :return:查到数据返回cursor,受影响的哪一行
        '''
        sql = "select * from FACE_INFO"
        cursor = sql_op.sqlite_exec_sql(conn, sql)
        return cursor
    
    def face_del(conn, face_name):
        '''
        根据图片名字删除指定的人脸数据
        :param conn: 数据库
        :param face_name:需要删除的图片的名字
        :return:如果删除成功返回True
        '''
        sql = "DELETE from FACE_INFO where NAME='" + face_name + "'"
        cursor = sql_op.sqlite_exec_sql(conn, sql)
        conn.commit()
    
    def face_del_by_id(conn, id):
        '''
        根据id删除指定的人脸数据
        :param conn: 数据库
        :param index: 需要删除的id索引
        :return:如果删除成功返回True
        '''
        sql = "DELETE from FACE_INFO where ID='" + str(id) + "'"
        cursor = sql_op.sqlite_exec_sql(conn, sql)
        conn.commit()
    
    def face_insert(conn, name, img_path):
        '''
        将人的相关信息(id,name,人脸图片)插入到数据库之中去
        :param conn: 该数据库的对象
        :param id: 唯一id
        :param name: 人脸的姓名
        :param img_path: 人脸的图片路径
        :return:True数据插入成功,Talse数据插入失败
        '''
        sql = "INSERT INTO FACE_INFO (NAME,IMAGE_PATH) VALUES (" +  "'" + name + "','" + img_path + "')"
        try:
            sql_op.sqlite_exec_sql(conn, sql)
        except sqlite3.IntegrityError as result:
            print("数据插入失败,原因:", result)
            return False
        else:
            conn.commit()
            return True
    
    def face_recognition():
        """
        实现人脸识别算法(打桩)
        :return: 返回此人的姓名
        """
        return 'Aaron_Eckhart_0001'
    
    def test_1():
        '''
        根据id查询信息的测试
        :return:
        '''
        conn = sql_con()
        b = face_query(conn, "小红")
        # print(b.fetchone())
        for pid, name, path in b:
            print(name)
            print(pid)
            print(path)
            pass
        conn.close()
    
    def test_2():
        '''
        删除测试
        :return:
        '''
        conn = sql_con()
        face_del_by_id(conn, 5)
        conn.close()
    
    def test_3():
        '''
        如果插入重复的数据,则报错误(使用异常)
        :return:
        '''
        coon = sql_con()
        flag = face_insert(coon, "小红", img_op.PATH2)
        if flag == True:
            print("插入成功")
        else:
            print("插入失败")
    
    def test_4():
        '''
        查询所有数据库的名字
        :return:
        '''
        conn = sql_con()
        cursor = face_query_all(conn)
        for id, name, path in cursor:
            print(id)
            print(name)
            print(path)
    
    if __name__ == '__main__':
        # test_1()
        # test_2()
        # test_3()
        test_4()
    
    

    4. 构建主界面(index.py)

    from tkinter import *
    from PIL import ImageTk, Image
    import aikit_main_face as face_rec
    import scan_op as scan_main
    import face_op
    FRAME_SIZE = "600x600"
    WEC_IMG = "img/weclome.jpg"
    
    
    def recon_img():
        face_rec.demo()
        pass
    
    
    def scan_dir():
        scan_main.scan_mulu_ui()
        pass
    
    
    def take_photo():
        scan_main.take_photo()
        pass
    
    
    def del_photo():
        ch = Toplevel()
        ch.title("删除数据")
        ch.geometry("200x200")
        Label(ch, text="你要删除的人名", width=30).pack()
        del_entry = Entry(ch, bg="lightblue")
        del_entry.pack()
        Button(ch, text="删除", command=lambda: del_data(del_entry.get())).pack()
        Button(ch, text="查询数据库", command=lambda: search_data()).pack()
        pass
    
    
    def del_data(name):
        conn = face_op.sql_con()
        face_op.face_del(conn, name)
        print("删除成功")
        conn.close()
        pass
    
    
    def search_data():
        conn = face_op.sql_con()
        cursor = face_op.face_query_all(conn)
        for id,name,path in cursor:
            print("id:{}, name:{}, path:{}".format(id, name, path))
            pass
        conn.close()
    
    
    def create_frame():
        app = Tk()
        app.title("人脸操作")
        app.geometry(FRAME_SIZE)
        app.configure(bg="skyblue")
    
        wec_image = Image.open(WEC_IMG)
        img = ImageTk.PhotoImage(wec_image)
        label = Label(app, image=img)
        label.pack(pady=15)
    
        # 建立上层框架
        frame_upper = Frame(app, bg="lightblue")
        frame_upper.pack(pady=15)
    
        scan_button = Button(frame_upper, text="扫描文件目录", width=28, height=3, command=lambda: scan_dir())
        scan_button.pack(side=LEFT, padx=15, pady=25)
    
        add_button = Button(frame_upper, text="添加人脸数据", width=28, height=3, command=lambda: take_photo())
        add_button.pack(side=LEFT, padx=15, pady=25)
    
        # 建立下层框架
        frame_lower = Frame(app, bg="lightblue")
        frame_lower.pack(pady=5)
    
        del_button = Button(frame_lower, text="删除人脸数据", width=28, height=3, command=lambda: del_photo())
        del_button.pack(side=LEFT, padx=15, pady=25)
    
        face_rec_button = Button(frame_lower, text="人脸识别", width=28, height=3, command=lambda: recon_img())
        face_rec_button.pack(side=LEFT, padx=15, pady=25)
    
        app.mainloop()
    
    
    if __name__ == '__main__':
        create_frame()
    

    4. 构建人脸识别函数(aikit_main_face.py)

    import os
    import cv2
    import face_recognition
    import face_op
    import scan_op
    path = "img/face_recognition"  # 模型数据图片目录
    
    
    # 加载人脸模型
    def load_face_models():
        total_image_name = []
        total_face_encoding = []
        conn = face_op.sql_con()
        cursor = face_op.face_query_all(conn)
        for id, name, path in cursor:
            print(id)
            print(path)
            total_face_encoding.append(
                face_recognition.face_encodings(
                    face_recognition.load_image_file(path)
                )[0]
            )
            fn = scan_op.get_name_by_path(path)
            total_image_name.append(fn)
        conn.close()
    
        # for fn in os.listdir(path):  # fn 表示的是文件名
        #     print(path + "/" + fn)
        #     total_face_encoding.append(
        #         face_recognition.face_encodings(
        #             face_recognition.load_image_file(path + "/" + fn))[0])
        #     fn = fn[:(len(fn) - 4)]  # 截取图片名(这里应该把images文件中的图片名命名为为人物名)
        #     total_image_name.append(fn)  # 图片名字列表
    
        return total_image_name, total_face_encoding
    
    
    def demo():
        total_image_name, total_face_encoding = load_face_models()
    
        cap = cv2.VideoCapture(0)  # 打开摄像头
        while True:
            ret, frame = cap.read()
            # 发现在视频帧所有的脸和face_enqcodings
            face_locations = face_recognition.face_locations(frame)
            face_encodings = face_recognition.face_encodings(frame, face_locations)
            # 在这个视频帧中循环遍历每个人脸
            for (top, right, bottom, left), face_encoding in zip(
                    face_locations, face_encodings):
                # 看看面部是否与已知人脸相匹配。
                for i, v in enumerate(total_face_encoding):
                    match = face_recognition.compare_faces(
                        [v], face_encoding, tolerance=0.5)
                    name = "Unknown"
                    if match[0]:
                        name = total_image_name[i]
                        break
                # 画出一个框,框住脸
                cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
                # 画出一个带名字的标签,放在框下
                cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255),
                              cv2.FILLED)
                font = cv2.FONT_HERSHEY_DUPLEX
                cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)
            # 显示结果图像
            cv2.imshow('Video', frame)
    
            # 按下'q'键退出程序
            key = cv2.waitKey(1) & 0xFF
            if key == ord('q'):
                break
    
        cap.release()
        cv2.destroyAllWindows()
    
    
    if __name__ == '__main__':
        demo()
    
    

    5. 构建另外几个界面(scan_op.py)

    import tkinter as tk
    from tkinter import *
    import img_op
    import face_op
    import camera
    coon = face_op.sql_con()
    on_hit = False
    
    def scan_file(scan_entry, var):
        global on_hit
        if on_hit == False:
            path = scan_entry.get()
            if path != '':
                var.set("正在扫描中...")
                img_op.scan_dir(path)
                print(img_op.img_file)
                var.set("扫描完成")
                on_hit = True
            else:
                print("你没有输入!")
        else:
            on_hit = False
            var.set("请输入你需要扫描的目录")
    
    
    def insert_sql_img(conn):
        for i in range(10):
            path = img_op.img_file[i]
            img_name = get_name_by_path(path)
            flag = face_op.face_insert(conn, img_name, path)
            if flag == True:
                print("插入{}信息成功".format(img_name))
    
    
    def del_sql_img(coon):
        '''
        通过人名删除图片在数据库的信息
        '''
        name = "Aaron_Eckhart_0001"
        flag = face_op.face_del(coon, name)
        if flag == True:
            print("删除{}信息成功".format(name))
            return True
    
    
    def get_name_by_path(path):
        '''
        通过路径获得名字
        :param path:
        :return:
        '''
        lindex = path.rfind("/") == -1 or path.rfind("\\")
        rindex = path.rfind(".")
        return path[lindex + 1:rindex]
    
    
    def search_sql_img(coon):
        '''
        通过人名查看图片的信息
        :return:
        '''
        name = search_entry.get()
        cursor = face_op.face_query(coon, name)
        print(cursor)
        for (id, name, path) in cursor:
            img = img_op.load_face_image_data(path)
            img_op.show_image(img)
    
    
    def recon_img():
        '''
        检测图片
        :return:
        '''
        name = face_op.face_recognition()
        if name == img_op.img_file[2]:
            messagebox.showinfo("识别成功")
        else:
            messagebox.showinfo("识别失败")
    
    
    def take_photo():
        photo = tk.Toplevel()
        photo.title("拍照")
        width = 600
        height = 400
        screen_x = photo.winfo_screenwidth()
        screen_y = photo.winfo_screenheight()
        x = (screen_x - width) / 2
        y = (screen_y - height) / 2
        photo.geometry("%dx%d+%d+%d" % (width, height, x, y))
        photo.configure(bg="skyblue")
        label = Label(photo, text="请输入拍照人的名字", width=30, height=2)
        label.pack(pady=20)
        get_name = Entry(photo, bg="lightblue")
        get_name.pack(pady=5)
        btn = Button(photo, text="拍照", command=lambda: camera.aikit_take_pictures(get_name.get()))
        btn.pack(pady=15)
        tishi = "拍照,按p实现拍照,并将图片存入数据库中,q退出拍照"
        tishi_label = Label(photo, text=tishi, width=30, height=6,wraplength=200, fg="red", font="16")
        tishi_label.pack()
        pass
    
    
    def scan_mulu_ui():
        face = tk.Toplevel()
        face.title("目录扫描")
        face.geometry('600x600')
        face.configure(bg="skyblue")
        scan_img = PhotoImage(file="img/timg (1).gif")
        scan_label = Label(face, image=scan_img)
        scan_label.pack(pady=25)
        var = tk.StringVar(value="请输入你需要扫描的目录")
    
        frame_up = Frame(face, bg="lightblue")
        frame_up.pack()
    
        scan_label = tk.Label(frame_up, textvariable=var, bg='pink', font=('Arial', 12), width=20, height=2)
        scan_label.pack(pady=15)
    
        scan_entry = tk.Entry(frame_up, bg='skyblue', font=('Arial', 12), relief=SUNKEN, width=25)
        scan_entry.pack(pady=5)
    
        scan_btn = tk.Button(frame_up, text="扫描", width=12, height=2, command=lambda: scan_file(scan_entry, var))
        show_btn = tk.Button(frame_up, text="显示", width=12, height=2, command=lambda: show_scan_content())
        scan_btn.pack(side=LEFT, pady=15)
        show_btn.pack(side=RIGHT)
        face.mainloop()
        pass
    
    if __name__ == '__main__':
        # scan_mulu_ui()
        # take_photo()
        pass
    

    6. 构建照相功能,存入数据库(camera.py)

    import cv2
    import face_op
    
    
    def aikit_take_pictures(name):
        print(name)
        rename = name + ".jpg"
        camera = cv2.VideoCapture(0)
        while True:
            ret, frame = camera.read()
            cv2.imshow("frame", frame)
            key_code = cv2.waitKey(1)
            if key_code & 0xff == ord('p'):
                cv2.imwrite(rename, frame)
                conn = face_op.sql_con()
                # 裁剪图片
                face_op.face_insert(conn, name, rename)
                conn.close()
                print("successful photo")
                pass
            if key_code & 0xff == ord('q'):
                break
                pass
            pass
        camera.release()
        cv2.destroyAllWindows()
        pass
    if __name__ == '__main__':
        pass
    

    总体就写完了

    展开全文
  • 人脸识别学习总结

    万次阅读 2019-05-03 13:02:48
    对人脸识别算法进行了一定程度学习,从最开始特征脸到如今CNN人脸检测,有了较为全面了解。重点掌握了基于PCA特征脸检测,LDA线性判别分析(Fisher线性判别),以及基于级联器Haar特征,LBP特征人脸...

       对人脸识别算法进行了一定程度的学习,从最开始的特征脸到如今的CNN人脸检测,有了较为全面的了解。重点掌握了基于PCA的特征脸检测,LDA线性判别分析(Fisher线性判别),以及基于级联器的Haar特征,LBP特征的人脸检测算法,人脸检测的学习主要是基于OpenCV中人脸识别类FaceRecognizer的学习。目前支持的算法有:

           Eigenface特征脸   createEigenFaceRecognizer()
           Fisherface             createFisherFaceRecognizer()
          LBP局部二值直方图    createLBPHFaceRecognizer()

    1、Eigenface特征脸(掌握PCA数学原理,人脸识别步骤)

           特征脸EigenFace:就相当于把人脸从像素空间变换到另一个空间,在另一个空间中做相似性的计算。EigenFace选择的空间变换方法是PCA,也就是大名鼎鼎的主成分分析。EigenFace方法利用PCA得到人脸分布的主要成分,具体实现是对训练集中所有人脸图像的协方差矩阵进行特征值分解,得到对应的特征向量,这些特征向量就是“特征脸”。

    1)将训练集的每一个人脸图像都拉长一列,将他们组合在一起形成一个大矩阵A。假设每个人脸图像是MxM大小,那么拉成一列后每个人脸样本的维度就是N=MxM大小了。假设有20个人脸图像,那么样本矩阵A的维度就是20xN了。                                 

    2)将所有的20个人脸求每一列的平均值,就得到了一个“平均脸”,这个“平均脸”矩阵E是一个1xN的向量,将这个向量reshape成MxM矩阵,你就可以把这个脸显示出来。                                  

    3)将20个图像都减去那个平均脸图像(即矩阵A的每一行减去向量E),得到差值图像的数据矩阵Φ,矩阵Φ的维度也是20xN。

    4)计算协方差矩阵 。协方差矩阵C的维度是NxN,(注意:协方差衡量的是不同像素位置间的相关性,并不是图像与图像之间的相关性)再对其进行特征值分解。就可以得到想要的特征向量(1xN)。这些特征向量如果还原成像素排列的话,其实还蛮像人脸的,所以称之为特征脸。我们可以取前40个特征向量,作为特征脸。                       

    5)将训练集图像和测试集的图像都投影到这些特征向量上了,再对测试集的每个图像找到训练集中的最近邻或者k近邻等处理,进行分类即可。

    实现步骤:

    1、读取训练样本
            注意一定要读取灰度图,并且转换成CV_32FC1

    2、求特征向量(特征脸)

    int number_principal_compent = 10;//保留最大的主成分数(特征向量数)
    //构造pca数据结构
    PCA pca(database, Mat(), CV_PCA_DATA_AS_ROW, number_principal_compent);
    Mat eigenvectors = pca.eigenvectors.clone();

    3、求出每个训练样本和测试样本在子空间中的投影系数
    Mat cv=pca.project(database);//输入database(m个样本)m*n,m张图像,返回cv是一个m*number_principal_compent 的向量
    Mat test = pca.project(testimage);//testimage是输入一张人脸图像:1*n,返回test是一个1*number_principal_compent 的向量,每个值代表该输入图像在每个特征脸上投影的系数。

    4、计算每个训练样本和测试样本的欧式距离,取其中最小的为识别图片。

    vector< double > distance
    for (int i = 0;i < cv.rows;i++)
            distance[i]=norm(test,cv.row(i));
    auto smallest = min_element(begin(distance), end(distance));
        cout << "min element is " << *smallest << " at position " << std::distance(std::begin(distance), smallest) << std::endl;        
    

    from:https://blog.csdn.net/weixiao2015/article/details/50282153 

    2、Fisherface

         Fisherface方法是主成分分析(PCA)与Fisher线性判别分析(FLD Fisher Linear Discriminant Analysis)相结合的算法。但也可以单独使用Fisher线性判别分析。

    LDA:(有监督,使用类别信息)

    基本思想是计算出使Fisher准则函数达到极值的向量,并将此向量作为最佳投影方向,样本在该方向上进行投影,投影后的特征向量具有类间离散度最大,类内离散度最小特点。

         假设有C个人的人脸图像,每个人可以有多张图像,所以按人来分,可以将图像分为C类,这节就是要解决如何判别这C个类的问题。判别之前需要先处理下图像,将每张图像按照逐行逐列的形式获取像素组成一个向量,设该向量为x,维数为n,x为列向量(n行1列)

        我们需要增加投影向量w的个数(当然每个向量维数和数据是相同的,),设w为: 

    w1、w2等是n维的列向量,所以w是个n行k列的矩阵,这里的k其实可以按照需要随意选取,只要能合理表征原数据就好。x在w上的投影可以表示为:,所以这里的y是k维的列向量。

          进行人脸识别时,将人脸向量投影到LDA子空间w,得到一个低维向量 :y=W^T_{lda}* x ,其中 W_{lda}=[w_{1},w_{2}....w_{p}],p\leq C-1

          在一个人脸集合上求得k=C-1个特征向量,如何匹配某人脸和数据库内人脸是否相似呢,方法是将这个人脸在k个特征向量上做投影,得到k维的列向量或者行向量,然后和已有的投影求得欧式距离,根据阈值来判断是否匹配。

    具体步骤:

    1、初始LDA对象,并根据输入样本计算最佳投影向量,即LDA子空间

    LDA(const Mat& src, vector<int> labels,int num_components = 0):_num_components(num_components)  
           {  
               this->compute(src, labels); //! compute eigenvectors and eigenvalues  
           }  

    参数num_components=0采用默认,由给定数据label的类别自动判决,如果类别为C,则默认值是C-1 

    2、LDA::project,将样本投影到到LDA子空间

    Mat LDA::project(InputArray src) {  
       return subspaceProject(_eigenvectors, Mat(), _dataAsRow ? src : src.getMat().t());  
    }  

    数据的处理:

    1、循环读入训练图像Mat,并将Mat对象存储到vector<Mat>容器中,同时新建一个Mat对象,或行矢量或列矢量来存储类别标签。

    2、将步骤1中的数据传入到LDA的构造函数中,构造函数进行计算处理,从而获得特征矢量。

    3、将训练数据利用project函数,投影到特征矢量构造的子空间,即LDA子空间,得到结果。

    4、利用project函数,将测试图像投影到LDA子空间,保存返回的Mat矢量,与训练数据得到的结果进行欧式距离比较,距离最小即为识别的人脸。

    总结:PCA是为了去除原始数据集中冗余的维度,让投影子空间的各个维度的方差尽可能大,也就是熵尽可能大。LDA是通过数据降维找到那些具有discriminative的维度,使得原始数据在这些维度上的投影,不同类别尽可能区分开来。

    LDA+PCA

            原始样本采用了200*200大小的图片,形成了40000维的特征矢量,其中包含了大量冗余信息和噪声,导致了LDA方法的不准确。因此一般先采用PCA降维:首先对原始样本图像进行PCA降维,而后再使用LDA进行分类训练;在进行测试时,也先对原始图像进行PCA降维,再利用LDA进行识别,这样可以有效消除冗余信息和噪声的干扰,压缩后的信息对脸部位置也变得不敏感。

          转换矩阵W_{opt},可以将样本投影到c-1维空间,其中c表示类别。

                                                             W_{opt}=W^T_{lda}W^T_{pca}

                                              投影公式为:z=W^T_{lda}W^T_{pca}(x-\mu )

         W_{lda}表示LDA的特征矢量构成的,W_{pca}表示PCA的特征矢量构成的,u是PCA分析中所有样本的均值。z列向量的维数为类别数目-1.注意:这里x是n*1列向量,W_{pca}是 n*(样本数−类别数)矩阵,temp=W^T_{pca}(x-\mu )得到(样本数−类别数)*1的列向量,实际上就是压缩后的人脸图像temp,z=W^{T}_{lda}*temp  (   W_{lda}=[w_{1},w_{2}....w_{p}],p\leq C-1,这里的W_{lda}是在pca降维后的人脸图像上求得的投影向量,矩阵尺寸为(样本数−类别数)*(类别数-1)

    from:https://blog.csdn.net/zdyueguanyun/article/details/8595549

    除了特征脸和Fisher线性判别外,人脸检测与识别有三个常用特征,分别是Haar,HOG,LBP。

    Haar

        Haar特征其实就是一组特征模板,模板由黑白两区域组成,每个模板代表一种Haar特征,用这些模板在图像上进行滑动,皆可以求出图像每个像素的不同种Haar特征响应,特征响应相当于模板与图像进行卷积,每个特征由白方块下的像素和减去黑方块的像素和来得到。 为了加速计算一般采用在积分图(掌握积分图计算)上进行求解。

        一般是用一个滑动子窗口遍历所有图像区域,求出每个待检测子窗口中的特征个数然后求出每个特征的特征值。矩形特征的数量只与子窗口的大小有关。在24×24的检测窗口中,矩形特征的数量约为160,000个。

    从这些特征中跳出最优的k个特征,每个特征就是一个弱分类器,使用adaboost算法挑选出m个(迭代m次)分类器,训练处权重,组成一个强分类器,重复adaboost训练处多个强分类器,级联起来。

                                          cascade.jpg
          首先将所有待检测的子窗口输入到第一个分类器中,如果某个子窗口判决通过,则进入下一个分类器继续检测识别,否则该子窗口直接退出检测流程。通过这样一种级联的方式可以去除一些误识为目标的子窗口,降低误识率。例如,单个强分类器,99%的目标窗口可以通过,同时50%的非目标窗口也能通过,假设有20个强分类器级联,最终的正确检测率为0.9920=98%,而错误识别率为0.5020≈0.0001%

      在一幅图像中,为了能够检测到不同位置的目标区域,需要以一定步长遍历整幅图像;而对于不同大小的目标,则需要改变检测窗口的尺寸,或者固定窗口而缩放图像。这样,最后检测到的子窗口必然存在相互重叠的情况,因此需要进一步对这些重叠的子窗口进行合并,也就是非极大值抑制(NMS,non-maximum suppression),同时剔除零散分布的错误检测窗口。

    HOG方向梯度直方图

    HOG特征的提取过程:

          1、Gamma归一化y=cx^{r}+b: 对图像颜色进行Gamma归一化处理,降低局部阴影及背景因素的影响.

          2、计算梯度:通过差分计算出图像在水平方向上及垂直方向上的梯度,然后得到各个像素点的梯度的幅值及方向                    

         3、划分cell 
         将整个图像窗口划分成大小相同互不重叠的细胞单元cell(如8×8像素),计算出每个cell的梯度大小及方向.然后将每像素的梯度方向在0−180(无向:0-180,有向:0-360)平均分为9个bins,统计每个cell的梯度直方图(不同梯度的个数),即可形成每个cell的descriptor. 

          4、组合成block,统计block直方图 

         将2×2个相邻的cell组成大小为16×16的像素块即block.依次将block大小的滑动框在整个图像窗口内,从左到右从上到下滑动,求其梯度方向直方图向量,一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征descriptor。

         对于64*128的图像而言,每8*8的像素组成一个cell,每2*2个cell组成一个block(16×16像素),因为每个cell有9个特征,所以每个block内有4*9=36个特征,以8个像素为步长,那么,水平方向将有7个扫描窗口(block),垂直方向将有15个扫描窗口(block),这样检测窗口block的数量有((128-16)/8+1)×((64-16)/8+1)=15×7。也就是说,64*128的图片,总共有36*7*15=3780个特征。
    HOG在行人检测和这里的检测中,一个是级联adaboost,另一个是SVM进行判别。

    LBP

         人脸特征还可以LBP直方图向量进行表达。在图像的每个像素点都可以得到一个LBP“编码”,那么,对一幅图像(每个像素点的灰度值)提取其原始的LBP算子之后,得到的原始LBP特征依然是“一幅图片”(每个像素点的LBP值)。然后将一幅图片划分为若干的子区域,在每个子区域内建立LBP特征的统计直方图。如此一来,每个子区域,就可以用一个统计直方图来进行描述;整个图片就由若干个统计直方图组成;之后,我们利用各种相似性度量函数,就可以判断两幅图像之间的相似性了,LBP即可以用于人脸检测,也可用于人脸识别。更多适用于检测,识别精度可能不高。


    怎样选择合适的算法做人脸检测

          最近人脸检测算法的流派包括三类以及这三类之间的组合:viola-jones(后面简称vj)框架,dpm和cnn。如果是为了在服务器上搭一个性能不错但是也要兼顾一些速度的人脸检测服务,建议搞cnn和vj这两个,因为dpm实在是太慢了,如果是dpm+cnn更是慢上加慢。相比之下,单独使用cnn就可以获得很不错的性能,同时如果有gpu服务器的话,速度也尚可。vj的话,性能一般但是速度是没问题的。如果准备在移动端or嵌入式上使用(就是计算能力,内存,甚至代码和模型大小都有限制),而且还想实时的话,基本上就只能选vj了,当然特征不一定要用haar。hog,lbp,pixel-difference以及一系列手工设计的特征都可以一战。其实如果待检测的人脸没有特别大幅度的姿态变化,传统的vj就够了,新的方法主要还是在表达能力(说白了就是能检测到更多千奇百怪的人脸)上增强了很多。如果你的人脸没那么奇怪(例如:严重遮挡、旋转的特别厉害、特别不清晰等等),用vj也就够了。  

    1、人脸检测技术的突破:VJ人脸检测器及其发展

    VJ人脸检测之所以器能够获得成功,极大地提高人脸检测速度,其中有三个关键要素:

       特征的快速计算方法——积分图,有效的分类器学习方法——AdaBoost,高效的分类策略——级联结构的设计。

    VJ人脸检测器采用Haar特征来描述每个窗口。

    1. 所谓Haar特征,其实就是在窗口的某个位置取一个矩形的小块,
    2. 然后将这个矩形小块划分为黑色和白色两部分,并分别对两部分所覆盖的像素点(图像上的每个点称为一个像素)的灰度值求和,
    3. 最后用白色部分像素点灰度值的和减去黑色部分像素点灰度值的和,得到一个Haar特征的值。

         在OpenCV级联分类器检测类CascadeClassifier中,使用Adaboost的方法+LBP、HOG、HAAR进行目标检测。

          Cascade器是通过将多个强分类器串联在一起,当样本满足所有分类器时,才能判别该样本是人脸,好处是:比如几乎99%的人脸可以通过,但50%的非人脸也可以通过,这样如果有20个强分类器级联,那么他们的总识别率为0.99^20约等于98%,错误接受率也仅为0.5^20约等于0.0001%。这样的效果就可以满足现实的需要了。

         强分类器的获取通过adaboost提升算法获得,强分类器是由多个弱分类器“并列”构成,即强分类器中的弱分类器是两两相互独立的。在检测目标时,每个弱分类器独立运行并输出,然后把当前强分类器中每一个弱分类器的输出值相加,这里的弱分类器其实就是Haar特征判别,CART树,仅有一个树桩节点(单个特征)

         如果直接利AdaBoost训练,那么工作量是极其极其巨大的,因为Haar特征太多。所以必须有个筛选的过程,筛选出T个优秀的特征值(即最优弱分类器),然后把这个T个最优弱分类器传给AdaBoost进行训练。

    弱分类器的选取过程: 对于每个特征 f,为该特征弱分类器选择使分类误差最小的阈值(最优阈值),此时我们的第一个最优弱分类器就诞生了,依次训练我么会得到每个特征的最优弱分类器。

        然后从这些最优弱分类器中挑选最好的T个分类器,分别送入多个Adaboost中进行训练。最终得到多个Adaboost强分类器(意思是:我们把选出的T个分类器分为10组,然后对每组的分类器分别进行Adaboost训练,这样最终我们会得到10个强分类器),最后将这些强分类器进行级联。

    2、DPM

    。。。

    3、CNN

          深度学习给目标检测任务点起了一把火,这个火种就是R-CNN。R对应于“Region(区域)”,意指CNN以图像区域作为输入。在检测方法上的变革。

    1、首当其冲的是抛弃了滑动窗口范式,取而代之的是一个新的生成候选窗口的环节。

        从某种意义上讲,VJ 人脸检测器中多个分类器相级联,每一级分类器都在为接下来的一级分类器提名候选窗口,但是这和 R-CNN 所采用的生成候选窗口的方式有一个重要的区别:

      实际上所有的窗口仍然都被检查了一遍,只是不断在排除,这是一种减法式的方案

      相比之下,R-CNN 采用的候选窗口生成方式,是根据图像的某些特征来猜测可能有哪些地方存在待检测的目标,以及这些目标有多大,这是一种从无到有的加法式的方案

    Selective Search是一种典型的候选窗口生成方法,其采用了图像分割的思路:

    先基于各种颜色特征将图像划分为多个小块,
    然后自底向上地对不同的块进行合并,
    在这个过程中,合并前后的每一个块都对应于一个候选窗口,
    最后挑出最有可能包含待检测目标的窗口作为候选窗口。

    2、第二点非常大的改变在特征提取上:不再采用人工设计的特征,而是用 CNN来自动学习特征。

        特征提取过程就是从原始的输入图像(像素颜色值构成的矩阵)变换到特征向量的过程,之前的如 Haar 特征等是科研工作者根据自己的经验和对研究对象的认识设计出来的,换言之人工定义了一个变换,而新的做法是只限定这个变换能够用CNN来表示

    好处:不仅避免了人工干预,解放了人力,而且有利于学习到更契合实际数据和目标的特征来,特征提取和分类两个环节可以相互促进,相辅相成;

    坏处:自动学习出的特征往往可解释性比较差,不能让人直观地去理解为什么这样提取出特征会更好,另外就是对训练集会产生一定程度的依赖。

    3、边框回归

    R-CNN在检测过程中引入了一个新的环节:边框回归(“框”念第四声),检测不再仅仅是一个分类问题,它还是一个回归问题:"回归和分类的区别就在于回归模型输出的不是离散的类别标签,而是连续的实数值。"

    边框回归指的是在给定窗口的基础上去预测真实检测框的位置和大小,也就是说:

          有了候选窗口之后,如果其被判别成了一个人脸窗口,那就会进一步被调整以得到更加精确的位置和大小——和待检测目标贴合得更好。边框回归一方面提供了一个新的角度来定义检测任务,另一方面对于提高检测结果的精确度有比较显著的作用。

    用R-CNN进行目标检测的流程是:

    1. 先采用如 Selective Search等方法生成候选窗口,
    2. 然后用学习好的CNN提取候选窗口对应的特征,
    3. 接着训练分类器基于提取的特征对候选窗口进行分类,
    4. 最后对判别为人脸的窗口采用边框回归进行修正。    

         虽然R-CNN带来了目标检测精度的一次巨大提升,然而由于所采用的候选窗口生成方法和深度网络都具有比较高的计算复杂度,因而检测速度非常慢。为了解决R-CNN的速度问题,紧接着出现了Fast R-CNN 和 Faster R-CNN,从名字上可以看到,它们的速度一个比一个快。

    1、在 Fast R-CNN 中,直接以整张图像作为输入,先得到整张图对应的卷积特征图, 然后对于每一个候选窗口,在提取特征时直接去整张图对应的卷积特征图上取出窗口对应的区域,从而避免重复计算, 之后只需要通过所谓的RoIPooling层来将所有的区域放缩到相同大小即可。(可以提供几十甚至上百倍的加速)

                  

    2、Fast R-CNN利用了一种名为 SVD 的矩阵分解技术,其作用是将一个大的矩阵(近似)拆解为三个小的矩阵的乘积,使得拆解之后三个矩阵的元素数目远小于原来大矩阵的元素数目,从而达到在计算矩阵乘法时降低计算量的目的,通过将 SVD应用于全连接层的权值矩阵,处理一张图片所需要的时间能够降低30%。 

                                              

    3、Faster R-CNN开始着眼于生成候选窗口的环节,其采用 CNN 来生成候选窗口,同时让其和分类、边框回归所使用的 CNN 共享卷积层,这样使得两个步骤中可以使用同样的卷积特征图,从而极大地减少计算量。  

    整体架构

     人脸识别概述:https://www.cnblogs.com/jesse123/p/5687069.html

    严格定义上的人脸识别分为四个步骤:

    ①人脸检测:从图片中准确定位到人脸

    ②人脸对齐: 自动定位出面部关键特征点

    ③进行特征提取

    ④对两张人脸图像的特征向量进行对比,计算相似度。

       人脸对齐任务即根据输入的人脸图像,自动定位出面部关键特征点,如眼睛、鼻尖、嘴角点、眉毛以及人脸各部件轮廓点等,并提取相应的部件特征。

    1、人脸关键点定位3000fps的LBF方法

    2、DCNN方法https://blog.csdn.net/qq_30815237/article/details/89709352,基于它改进算法,将人脸分为内部点和轮廓点;

    对人脸检测MTCNN算法做一个简要研究。该MTCNN算法出自深圳先进技术研究院,乔宇老师组,是今年2016的ECCV。

     

    展开全文
  • 一 行业分析 1 行业定义 中软高科属于人脸识别行业人脸识别是基于人的脸部特征信息进行身份识别的一种 生物识别技术用摄像机或摄像头采集含有人脸的图像或视频流并自动在图像中检测 和跟踪人脸进而检测到的人脸...
  • 人脸识别相关方向已经有一年了,从开始懵懂无知,通过一次又一次不断踩坑终于有了一定得了解与认识,可能这也是相对浅显与青涩.为了让自己一些知识巩固更深,也希望能帮助更多类似我这样初学者,自此...

    做人脸识别相关方向已经有一年了,从开始的懵懂无知,通过一次又一次的不断踩坑终于有了一定得了解与认识,可能这也是相对浅显与青涩的.为了让自己对一些知识巩固更深,也希望能帮助更多的类似我这样的初学者,自此开始写一些文章记录我自己的学习历程。

    一.生物特征识别简述

    自人类社会出现以来,确认某个人的身份就成了社会分配中最为基础也最为重要的一项技术要求。例如,分配资源时,确认某人身份而确定他是否具有资格等。

    在原始社会初期,人们天然地会利用他人的面目,声音,乃至走路姿态,身形而确认他人身份,但是当社会不断进步,人类居住范围不断增加,需求不断扩大,需要确认身份的应用场景也越来越多:出入境安检,万恶的考试以及各种报名,分发福利,各种注册等等场合不断更新,从此证明你自己是你自己变得越来越重要,也就是说,你自己是谁不再被关心,而是要向别人说明你自己是谁才值得关注,这就需要一定的凭证,即你和你的凭证的关系就是个人和身份之间的关系。为此三种类型的凭证应运而生。

    第一种凭证:有些东西你知道别人都不知道(knowledge-based)。利用一些只有该对象知道而别人不知道的信息来确定能够某人身份是常用手段之一。银行卡密码,身份证号这些都是属于这一范畴。

    第二种凭证:你有的而别人没有的东西(token-based)。有些东西只有你有而别人没有,利用它,你能展示自己的身份。身份证,驾照,钥匙这些都是属于这一范畴。

    第三种凭证:是你天生就有而别人没有的(Biometrics)。这些是你天生的凭证,最原始的时候,我们天生的就利用这些特性去判断别人身份。比如 人脸,指纹,声音等等。

    其实这三类并不是割裂的,比如身份证,他是一个你有而别人不能有的东西(是指你自己的身份证,前提不被偷,不被造假),它上面有你知道而别人不知道的东西身份证号,还有你的人脸,一个你本来天生有的东西。那是不是可以说早先大家就biometrics了?当然不能完全这么说,生物特征识别就我理解是仅仅使用生物其实也就是人类的某些特征进行识别的一项技术 。例如,只需要你的指头轻轻一点,就完成了认证。

    需要说的一点是,天下没有百分之百可靠的识别方式。而我们现在推崇生物特征识别,只是一定程度上优于前两者,哪有那些先进性:

    1.前两者易于忘记或者丢失。比如现在各类账户巨多,若是所有账户同一密码,危险性很高,若不是同一密码,记忆是一件困难的事,与之类似的各类卡片容易丢失,携带也不方便。但生物特征识别中,你固有的特性不易丢失损坏。天然携带方便。

    2.前两者容易造假,或者被盗,被抢。比如身份证可以被伪造,甚至被抢,破译密码也相对简单。但是仿造人脸,仿造指纹,相对复杂一些(不过近几年,指纹造假也挺严重)。

    3.对于前两者,易于出现不配合的情况。比如可以让同学代替上课刷卡,违章人员拒绝出示证件企图规避处罚。但是你可以说自己忘带身份证,但是不能说自己脸忘带了。所以生物特征识别具有抗不配合的性质。

    以上几点只是简单地总结了生物特征识别的优点。下面陈述什么是识别。大家对于识别是有一个模糊概念的就是说通过一个凭证说明自己是谁,但这一概念可以被具象化,在现实生活场景中主要出现两种场景:Identification(鉴别场合)和Verification(核实场合)。

    对于前者来说就是你是不是某个集合中的某个人?比如上班打卡就是你要证明你是这个单位中的某个人,比如在犯有前科的数据库中,你就要证实你自己不是这个库中的某个人。而对于后者而言就是你要证明你是你自己宣称的那个人,比如领取快递,你通过身份证或手机号证明你自己是物主。


    展开全文
  • 漫画人脸识别近几年的一些文章简介,算是这些文章的一些方法一级数据库构建方面的总结吧。
  • 第一个是苹果的FACE ID,自从苹果推出FaceID后,业界对人脸识别的应用好像信心大增,各种人脸识别的应用从此开始“野蛮生长”。 事实上,人脸识别技术在很多场景的应用确实可以提升认证效率,同时提升用户体验。前...

    1人脸识别应用场景(验证)

    我们先来看看人脸识别的几个应用。第一个是苹果的FACE ID,自从苹果推出FaceID后,业界对人脸识别的应用好像信心大增,各种人脸识别的应用从此开始“野蛮生长”。

    事实上,人脸识别技术在很多场景的应用确实可以提升认证效率,同时提升用户体验。前两年,很多机场安检都开始用上了人脸验证;今年4月,很多一、二线城市的火车站也开通了“刷脸进站”的功能;北京的一些酒店开始使用人脸识别技术来做身份验证。

    2 人脸识别应用场景(识别)

    我们再来看看几个场景。

    第一个是刷脸的自动售货机。当我第一次看到这个机器的时候就有个疑问:”现在人脸识别算法已经做到万无一失了吗,认错人,扣错钱怎么办?”,后来才发现,其实关键不在于算法,产品设计才是最重要的。用过这个售货机的人可能知道,第一次使用的时候,要求输入手机号的后四位,这个看似简单的产品设计,可以让自动售货机的误识别率降低到亿分之一,这样底概率的条件下,误识别带来的损失完全可以忽略。同时这款自动售货机还会提醒你,你的消费行为会绑定“芝麻信用”,想想有几个人会为了一瓶“可乐”去影响自己的征信记录呢?

    第二个是刷脸买咖啡,进入咖啡店后,在你选好喝什么咖啡前,系统已经识别出站在点单台前的用户是谁,并做好点单准备;

    第三个是在人脸门禁系统。小伙伴们再已不用担心忘记带工卡了。人脸门禁对识别速度和准确度的要求是相对较高的,设备挂在门的侧面墙也会影响体验,增加产品设计和开发的难度。

    3 “人脸验证”还是“人脸识别”?

    其实,前面两页的场景是有些区别的,不知道大家看出来了没有。

    第一个的场景,用户实际提供了两个信息,一是用户的证件信息,比如身份证号码,或APP账号;另一个信息是用户的现场照片;这类场景的目标实际上是:让人脸识别系统验证现场照片是否是证件所宣称的那个人。我们把这类场景叫着“人脸验证”

    第二个的场景,用户实际只提供的现场照片,需要人脸识别系统判断照片上的人是谁。我们把这类场景叫着“人脸识别”

    “人脸验证”拿现场人脸跟用户所宣称的人脸做1比1的比较,而“人脸识别”是拿现场人脸跟后台注册人脸库中的所有人脸比较,是1比N的搜索。可以看出,两种场景的技术原理一致,但是难度不同,第二页场景的难度普遍比第一页高得多。

    4 人脸识别原理

    计算机是怎么识别人脸的呢?如果我们大家是人脸识别系统的设计者,我们应用怎样来设计这个系统?

    “把人脸区域从图片中抠出来,然后拿抠出来的人脸跟事先注册的人脸进行比较”,没错,就是这样,说起来简单,做又是另外一回事了,这里又有两个新的问题:

    一是,“怎样判断图片中是有没有人脸?”,“怎样知道人脸在图片中的具体位置呢”,这是人脸检测要解决的问题,人脸检测告诉我们图像中是否有人脸以及人脸的具体位置坐标。

    二是,“我们怎样比较两个人脸是不是同一个人呢?”,一个像素一个像素比较吗?光照,表情不一致,人脸偏转都将导致该方法不可行。”人是怎样判断两种照片中的人脸是不是同一个人的呢?”,我们是不是通过比较两种照片上的人,是不是高鼻梁、大眼睛、瓜子脸这样的面部特征来做判断的呢? 

    我们来看一下计算机人脸识别的流程,首先是获取输入图像,然后检测图像中是否有人脸,人脸的具体位置,然后判断图像的质量,比如图像是否模糊,光照度是否足够,然后检测人脸偏转的角度,旋转人脸到一个正脸位置,再然后提取人脸特征,比对人脸特征,最后输出识别结果。其中图像质量检测和人脸对齐这两步是可选的步骤,根据具体应用场景来决定。

    5 人脸检测-经典方法

    我们来看看经典的人脸检测方法。

    OpenCV和Dlib是两个常用的算法库。

    OpenCV 中使用Haar Cascade来做人脸检测,其实Haar Cascade可以检测任何对象,比如人脸和脸上眼睛的位置。

    DLIB中是使用方向梯度直方图(Histogram of Oriented Gradient, HOG),即通过计算图像局部区域的梯度方向直方图来提取特征,这种方法的本质在于梯度的统计信息,而梯度主要存在于边缘的地方。

    OpenCV和DLIB各自也有他们自己的基于深度学习的人脸检测方法,使用起来非常简单。从这几种方法都可以做到CPU实时或GPU实时;经典的检测方法对正脸的检测效果比较好,深度学习的方法适应性更强,可以检测各种角度的人脸

    6 MTCNN人脸检测

    2016年提出来的MTCNN算法是目前公认比较好的人脸检测算法是(Multi-task Cascaded Convolutional Networks),可以同时实现face detection和alignment,也就是人脸检测和对齐。

    这里的对齐指的是检测人脸眼睛、鼻子、嘴巴轮廓关键点LandMark。

    MTCNN算法主要包含三个子网络:P-Net (Proposal Network)、 R-Net(Refine Network)、O-Net(Output Network),这3个网络按照由粗到细的方式处理输入照片,每个网络有3条支路用来分别做人脸分类、人脸框的回归和人脸关键点定位

    左上角,最开始对在多个尺度上对图像做了resize,构成了图像金字塔,然后这些不同尺度的图像作为P、P、O网络的输入进行训练,目的是为了可以检测不同尺度的人脸

    P-Net主要用来生成候选人脸框。 R-Net主要用来去除大量的非人脸框。O-Net和R-Net有点像,在R-NET基础上增加了landmark位置的回归,最终输出包含一个或多个人脸框的位置信息和关键点信息

    7 人脸特征提取-经典方法

    接下来,我们来看一下人脸特征提取。经典的人脸特征提取方法有EigenFace和FisherFace两种。

    EigenFace的思想是把人脸从像素空间变换到另一个空间,在另一个空间中做相似性的计算。EigenFace的空间变换方法是主成分分析PCA。这个方法90年代开始应用于人脸识别,因为主成分有人脸的形状,所以也称为“特征脸”。

    FisherFace是一种基于线性判别分析LDA(全称Linear  Discriminant Analysis,)的人脸特征提取算法, LDA和PCA都是利用特征值排序找到主元的过程。LDA强调的是不同人脸的差异而不是照明条件、人脸表情和方向的变化。所以,Fisherface对人脸光照、人脸姿态变化的影响更不敏感。

    8 人脸特征提取-深度学习法

    我们再来看看深度学习法。

    利用神经网络学习高度抽象的人脸特征,然后将特征表示为特征向量,通过比较特征向量之间的欧式距离来判定两张照片是否是同一个人

    9人脸特征提取-深度学习法

    总体思路是把人脸识别人物当分类任务来训练,通过在损失函数上施加约束,让相同的人的照片提取的特征距离尽可能近,不是同一个人的照片的提取的特征距离尽可能的远

    第一个Logit的地方输出的是人脸的特征向量,一般是128维或者512维,浮点向量。这个Logit前面是CNN分类网络,这个Logit后面的部分是通过在损失函数上施加约束来训练模型,让模型区分相同的人和不同的人,后面的部分只需要在训练阶段计算,推理阶段是不需要的。

    10 人脸特征提取-Metric Learning

    基于深度学习的人脸特征提取方法主要有两类,一类Metric Learning,另一个是Additive Margin,这两类方法的底层原理都是一样的,就是“通过训练网络,让相同人的特征距离尽可能近,不同人的特征距离尽可能的远”。

    孪生网络和Triplet都属于 Metric Learning这类方法。左边孪生网络顾名思义,就是有两个网络,一个网络训练让相同的人之间的距离尽可能的近,另一个网络让不同人之间的距离尽可能远。

    右边Triplet网络是对孪生网络的改进,将样本组织为锚点、正样本、负样本的元组,通过训练网络让锚点与正样本之间的距离尽可能的近,锚点与负样本之间的距离尽可能的远,并且至少远于一个阀值阿尔法。

    11 人脸特征提取-Additive Margin

    Additive Margin这类方法主要是在分类模型的基础,通过控制损失函数来达到“让相同人的特征距离尽可能近,让不同人的特征距离尽可能远”的目标。

    前面介绍的Metric Learning的方法最大的问题在于:需要重新组织样本,模型最终能否收敛很大程度上取决于采样是不是合理。基于Additive Margin的方法则不需要这一步,完全将人脸特征提取当做分类任务来训练,参数的设置也不需要太多trick,Additive Margin的方法大都是在损失函数上做文章。

    最近几年,这个类方法研究的比较多,上面这个图中的softmax,Sphereface,Cosface,ArcFace都是Additive Margin方法,可以看出它都是通过改进损失函数,来实现“让相同人的特征距离尽可能近,让不同人的特征距离尽可能远”这个目标

    上面这个图中,颜色相同的点表示一个人,不同的点表示不同的人,这个图的展示比较形象,可以看出最后一个超球体的效果非常不错

    Additive Margin正在成为主流, InsightFace也属于这一类,损失函数正是这个ArcFace。

    大家可用思考一下,为什么分类方法不能直接用于人脸识别?这里不做详细讨论了。

    12 人脸特征提取-效果评估

    我们再来看一下怎样评估人脸特征提取算法的效果。

    主要是通过召回率和虚警率两个指标来衡量。应用场景不同,这个两个指标的设置也不同,一般情况下,在实践中我们都要求在虚警率小于某个值(比如万分之一)的条件下,召回率达到某个值(比如99%)。很多产品宣称的识别准确率达到多少多少,很大可能是在公开数据集比如LFW上的测试结果。

    公开的训练数据集比较推荐的有:MS1MV2,这个数据集微软前段事件已经宣布撤回不再提供下载,这个数据集大概有85000个不同的人的380万张照片。另一个数据集是GLINT_ASIA,有9万多人的280万张照片。

    13 工程实践的挑战及经验分享

    很多人都认为人脸识别应用,算法包打天下,事实并非如此,即使是最好的识别算法也扛不住像图像质量差。图像质量差、姿势变化、面部形状/纹理随着时间推移的变化、遮挡这些问题,是我们在工程实践中面临的挑战。

    当然,大多数问题工程上我们有应对方法。比如图像模糊,光照不足,我们可以先检测图像是否模糊,关照是否不足,质量不过关,就不把图像送给识别算法。

    再比如,用他人照片或视频来欺骗人脸识别系统,目前已经有多种活体检测方法来检测并防止这种情况。

    经过一段时间在人脸识别领域的摸爬滚打,个人认为影响用户体验的关键因素是识别快、识别准,识别快主要靠产品设计,识别准主要靠算法

    拿人脸门禁来举个例子,产品设计上可以在前端采集照片的时候过滤掉模糊、无人脸的照片,避免无效识别,同时前端在采集照片的时候,可以同时采集多张并发传给后台,做并发识别,这些方法都可以大大提升识别通过的速度,提升用户体验。

    展开全文
  • 基于全局信息的人脸识别总结

    千次阅读 热门讨论 2007-10-29 12:19:00
    黄叶权 整理于 2007年6月一、 课题名称基于全局信息的人脸识别算法研究二、 课题提出在当今社会中,身份确认具有十分重要价值。随着网络技术发展,信息安全也显示出了前所未有重要性。在经济、政府、安防和...
  • 作者根据多年人脸识别项目经验,总结人脸识别技术在安防、商业领域应用及产品设计细节,汇总成应用层下的人脸识别系列文章。本文为系列文章第四篇,从什么是人脸研判及人脸研判类型和应用两方面介绍相关内容。一...
  • 英国赫特福德大学与 GBG Plc 研究者近日发布了一篇综述论文,对人脸识别方法进行了全面梳理和总结,其中涵盖各种传统方法和如今风头正盛深度学习方法。机器之心重点编译介绍了其中深度学习方法部分,更多...
  • 第一个是苹果的FACE ID,自从苹果推出FaceID后,业界对人脸识别的应用好像信心大增,各种人脸识别的应用从此开始“野蛮生长”。事实上,人脸识别技术在很多场景的应用确实可以提升认证效率,同时提升用户体验。前两...
  • opencv人脸识别总结2

    2015-02-04 22:31:46
    今日总结: 今天工作比昨天更水了点,就是把create方法添加了两个参数(createEigenFaceRecognizer(num_components_defalut,threshold_defalut);), 方便后续工作中用progressbar来控制。 然后后续计划做了...
  • 本文是饶昊宸同学文章《Eigenfaces vs. Fisherfaces: Recognition Using Class Specific Linear ...人脸识别问题可以被视为一个分类问题,描述如下:人脸识别就是根据学习给定人脸图片样本(训练集)来...
  • 人脸识别在深度学习领域里算是一项较为成功的应用,在日常生活中,经常可以见到人脸识别的设备,如人脸考勤机,各大交通站点的闸机,移动支付等。本人在从事人脸识别算法开发的短短一年时间里,也关注了不少论文和...
  • 实用标准文案 人脸识别技术综述 李勃 摘要简要介绍了人脸识别技术研究背景及其发展历程 对人脸识别技术常用方法进行 了分类总结 重点对近年来人脸识别方法研究进展进行综述并对各种方法加以评价 总结 了现阶段...
  • 第一个是苹果的FACE ID,自从苹果推出FaceID后,业界对人脸识别的应用好像信心大增,各种人脸识别的应用从此开始“野蛮生长”。事实上,人脸识别技术在很多场景的应用确实可以提升认证效率,同时提升用户体验。前两...
  • 作者:wjmishuai 出处:http://blog.csdn.net/wjmishuai/article/details/50854168 声明:版权所有,转载请注明出处 代码下载地址:...  现在,有很多关于人脸识别的卷积神经网络,我首先需要
  • 基于matlab的人脸识别

    2013-04-19 20:38:40
    本文介绍了人脸图像识别中所应用MATLAB图像进行预处理,应用该工具箱图像进行经典图像处理,通过实例来应用matlab图像处理功能,某一特定人脸图像处理,进而应用到人脸识别系统。本文在总结分析人脸识别系统...

空空如也

空空如也

1 2 3 4 5 ... 18
收藏数 344
精华内容 137
关键字:

对人脸识别的总结