赞
踩
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进行格式转换。
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()
输出结果(演示结果是导进去两张静态图片出来的结果):
备注:将自己的图片进行导入,便可以看到实际效果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。