Fork me on github

python人脸识别:对完成一个简单的人脸识别项目总结

简单的人脸识别项目

附上我的思维导图
在这里插入图片描述
附上我的项目路径
在这里插入图片描述
其中我的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

总体就写完了

posted @ 2022-01-23 11:59  不想努力的小龙  阅读(334)  评论(0编辑  收藏  举报