人脸识别之数据库存取

6 篇文章 0 订阅
6 篇文章 0 订阅

一、程序概况

1.将人脸特征信息保存进MySQL数据库。

2.调用摄像头识别人脸,将待识别的人物进行识别,并实时地与数据库中的人脸特征信息进行比对,同时判断出被识别者的身份。

二、程序分析

1.主要利用opencv、face_recognition、numpy、pymysql等Python第三方类库,官方说法是face_recognition的人脸识别准确率高达99.6%。

2.利用face_recognition,可以很轻易地得到人脸128维的人脸编码,并且通过比对函数,就可以得出想要的结果。但是,128维的人脸编码是一个numpy ndarray类型,即矩阵,并不能存进数据库,要想存进数据库,必须进行类型转换,我的做法是先将矩阵转为列表,再将列表里的每个元素转为字符串,再用字符串拼接的方式拼成一个字符串,这时就可以把特征值存进数据库了。

3.既然是特征值的比对,那么从数据库取完数据之后,就需要把字符串重新转为矩阵格式,我的做法是先通过字符串切割,转为列表,再对列表里每个元素转为浮点型(float),最后再转为矩阵。

4.常规做法通过人脸识别后想要在图像上输出被识别者姓名,但是opencv有自己的一套编码规范,无法输出中文,如果保存的是中文,那么就会出现乱码的情况。出于强迫症,我就是要输出中文。我的做法是通过调用本地已存在的字体,利用PIL进行格式转换。

 三、环境搭建(基于Ubuntu系统):

1.如果没有安装pip3,请使用以下命令进行安装:

   安装pip3:sudo apt-get install python3-pip

   升级pip3:sudo pip3 install --upgrade pip

2.安装boost库:sudo apt-get install libboost-all-dev

3.安装cmake:sudo apt-get install cmake

4.安装dlib:sudo pip3 install dlib

5.安装opencv:sudo pip3 install opencv_python==3.4.2.16

6.安装PyMySQL:sudo pip3 install PyMySQL

7.安装face_recognition:sudo pip3 install face_recognition

备注:安装face_recognition过程中会自动安装numpy、scipy等

四、准备工作

对于MySQL数据库的操作采用Navicat可视化工具,数据库为test,表为face。

如图:

附Navicat安装教程:https://blog.csdn.net/superit401/article/details/78110079/

解决Navicat中文乱码教程:https://blog.csdn.net/sinat_26546385/article/details/80381282

五、程序代码

1.feature.py #将人脸特征保存进数据库

import face_recognition
import pymysql


# 加载图像及获取人脸特征
def load_image(input_image, input_name):
    # 加载本地图像文件到一个numpy ndarray类型的对象上
    image = face_recognition.load_image_file(input_image)

    # 返回图像中每个面的128维人脸编码
    # 图像中可能存在多张人脸,取下标为0的人脸编码,表示识别出来的最清晰的人脸
    image_face_encoding = face_recognition.face_encodings(image)[0]

    # 将numpy array类型转化为列表
    encoding__array_list = image_face_encoding.tolist()

    # 将列表里的元素转化为字符串
    encoding_str_list = [str(i) for i in encoding__array_list]

    # 拼接列表里的字符串
    encoding_str = ','.join(encoding_str_list)

    # 被识别者姓名
    name = input_name

    # 将人脸特征编码存进数据库
    save_encoding(encoding_str, name)


# 人脸特征信息保存
def save_encoding(encoding_str, name):
    # 创建数据库连接对象
    conn = pymysql.connect(
        # 数据库的IP地址
        host="127.0.0.1",
        # 数据库用户名称
        user="root",
        # 数据库用户密码
        password="123456",
        # 数据库名称
        db="test",
        # 数据库端口名称
        port=3306,
        # 数据库的编码方式 注意是utf8
        charset="utf8"
    )

    # 使用 cursor() 方法创建一个游标对象 cursor
    cursor = conn.cursor()

    # SQL插入语句
    insert_sql = "insert into face(name,encoding) values(%s,%s)"
    try:
        # 执行sql语句
        cursor.execute(insert_sql, (name, encoding_str))
        # 提交到数据库执行
        conn.commit()
    except Exception as e:
        # 如果发生错误则回滚并打印错误信息
        conn.rollback()
        print(e)

    # 关闭游标
    cursor.close()
    # 关闭数据库连接
    conn.close()


if __name__ == '__main__':
    load_image("yangchaoyue.jpg", "杨超越")
    load_image("zhangyishan.jpg", "张一山")

将以下两张图片中人物的人脸特征存入数据库

        

此时已经将人物的人脸特征存入到数据库中

2.recognition.py #人脸识别程序

import face_recognition
import cv2
import pymysql
import numpy as np
from PIL import Image, ImageDraw, ImageFont

# 人脸特征编码集合
known_face_encodings = []

# 人脸特征姓名集合
known_face_names = []


# 从数据库获取保存的人脸特征信息
def get_info():
    # 创建数据库连接对象
    conn = pymysql.connect(
        # 数据库的IP地址
        host="127.0.0.1",
        # 数据库用户名称
        user="root",
        # 数据库用户密码
        password="123456",
        # 数据库名称
        db="test",
        # 数据库端口名称
        port=3306,
        # 数据库的编码方式 注意是utf8
        charset="utf8"
    )

    # 使用 cursor() 方法创建一个游标对象 cursor
    cursor = conn.cursor()

    # SQL查询语句
    sql = "select * from face"
    try:
        # 执行SQL语句
        cursor.execute(sql)
        # 获取所有记录列表
        results = cursor.fetchall()
        # 返回的结果集为元组
        for row in results:
            name = row[1]
            encoding = row[2]
            # print("name=%s,encoding=%s" % (name, encoding))
            # 将字符串转为numpy ndarray类型,即矩阵
            # 转换成一个list
            dlist = encoding.strip(' ').split(',')
            # 将list中str转换为float
            dfloat = list(map(float, dlist))
            arr = np.array(dfloat)

            # 将从数据库获取出来的信息追加到集合中
            known_face_encodings.append(arr)
            known_face_names.append(name)

    except Exception as e:
        print(e)

        # 关闭数据库连接
        conn.close()


# 加载视频图像
def load_image():
    #  打开摄像头 0代表笔记本的内置摄像头,1代表外置摄像头
    video_capture = cv2.VideoCapture(0)

    # 得到特征信息
    get_info()

    process_this_frame = True

    while True:
        # 读取摄像头画面
        ret, frame = video_capture.read()

        # 利用opencv的缩放函数改变摄像头图像的大小,图像越小,所做的计算就少
        small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)

        # opencv的图像是BGR格式的,而我们需要是的RGB格式的,因此需要进行一个转换。
        rgb_small_frame = small_frame[:, :, ::-1]

        # 处理每一帧的图像
        if process_this_frame:
            # 使用默认的HOG模型查找图像中的所有人脸
            face_locations = face_recognition.face_locations(rgb_small_frame)
            # 如果硬件允许,可以使用GPU进行加速,此时应改为CNN模型
            # face_locations = face_recognition.face_locations(image, number_of_times_to_upsample=0, model="cnn")

            # 返回128维人脸编码,即人脸特征
            face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)

            face_names = []

            # 将得到的人脸特征与数据库中的人脸特征集合进行比较,相同返回True,不同返回False
            for face_encoding in face_encodings:

                # matches:一个返回值为True或者False值的列表,该表指示了known_face_encodings列表的每个成员的匹配结果
                # tolerance:越小对比越严格,官方说法是0.6为典型的最佳值,也是默认值
                # 这里我设置0.45为最佳,可能跟我硬件有关
                matches = face_recognition.compare_faces(known_face_encodings, face_encoding, tolerance=0.45)
                # 默认为unknown
                name = "Unknow"

                if True in matches:
                    first_match_index = matches.index(True)
                    name = known_face_names[first_match_index]
                    print('已存在')
                else:
                    print('不存在')

                face_names.append(name)

        process_this_frame = not process_this_frame

        # 将捕捉到的人脸显示出来
        for (top, right, bottom, left), name in zip(face_locations, face_names):
            # 恢复显示的图像大小
            top *= 4
            right *= 4
            bottom *= 4
            left *= 4

            # CV库有自己的编码规范,要想在图像上输出中文,需将图片格式转化为PIL库的格式,用PIL的方法写入中文,然后在转化为CV的格式
            # cv2和PIL中颜色的hex码的储存顺序不同
            cv2img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            pilimg = Image.fromarray(cv2img)

            # PIL图片上打印汉字
            draw = ImageDraw.Draw(pilimg)
            # NotoSansCJK-Light.ttc为本机上已有的字体,可通过locate *.ttc进行查询
            font = ImageFont.truetype("NotoSansCJK-Light.ttc", 30, encoding="utf-8")  # 参数1:字体文件路径,参数2:字体大小
            draw.text((left + 10, top - 40), name, (255, 255, 255), font=font)  # 参数1:打印坐标,参数2:文本,参数3:字体颜色,参数4:字体

            # PIL图片转cv2 图片
            frame = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR)

            # 对人脸画出矩形框
            cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2)

            # 如果只想输出英文,可以省略以上步骤,编写以下代码即可
            # 显示的字体类型
            # font = cv2.FONT_HERSHEY_TRIPLEX
            # 打印识别信息
            # cv2.putText(frame, name, (left + 6, top - 6), font, 1.0, (255, 255, 255), 1)

        # 显示图像
        cv2.imshow('monitor', frame)

        # 按Q退出
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    # 释放摄像头资源
    video_capture.release()
    # 关闭显示图像的窗口
    cv2.destroyAllWindows()


if __name__ == '__main__':
    load_image()

输出结果(演示结果是导进去两张静态图片出来的结果):

备注:将自己的图片进行导入,便可以看到实际效果

                             

 

  • 33
    点赞
  • 258
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 19
    评论
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西瓜不甜柠檬不酸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值