人脸识别(具体版)
前面我们只去检测了人脸,但是没有对人脸具体识别出是张三的还是李四的,所以这里我们来对一个人脸进行识别出具体归于谁。
这里也用到了深度学习的模型
opencv提供的算法
Opencv提供了三种用于识别人脸的特征提取算法。分别是 LBPH 算法、EigenFaces 算法、FisherFaces 算法。
1 LBPH(Local Binary Patterns Histogram,
局部二值模式直方图)算法使用的模型基于LBP(Local Binary Pattern,局部二值模式)算法。LBP 算法最早是被作为一种有效的纹理描述算提出的,因在表述图像局部纹理特征方面效果出众而得到广泛应
详述
1、以每个像素为中心,判断与周围像素灰度值大小关系,对其进行二进制编码,从而获得整幅图像的LBP编码图像; 2、再将LBP图像分为n个区域,获取每个区域的LBP编码直方图,继而得到整幅图像的LBP编码直方图。 通过比较不同人脸图像LBP编码直方图达到人脸识别的目的,其优点是不会受到光照、缩放、旋转和平移的影响。
看着复杂,其实内容也挺复杂的,我们先对图片进行一遍遍历,找出一个阈值,高于的设1 低于的为0,如何求出LBP值,如何根据这个写出二进制值,然后顺时针旋转。找出最小的二进制值设为这一个的特征。然后然后根据数据和标签训练出一个模型。就可=可以预测图片了。
2 EifenFaces算法
Eigenfaces是在人脸识别的计算机视觉问题中使用的一组特征向量的名称,Eigenfaces是基于PCA(主成分分析)算法实现的。
主成分分析(PCA)是一种矩阵的压缩算法,在减少矩阵维数的同时尽可能的保留原矩阵的信息,简单来说就是将 n×m的矩阵转换成n×k的矩阵,仅保留矩阵中所存在的主要特性,从而可以大大节省空间和数据量
3 Fisherfaces
采用LDA(Linear Discriminant Analysis,线性判别分析)实现人脸识别。 其基本原理:在低维表示下,首先将训练集样本集投影到一条直线A上,让投影后的点满足: 同类间的点尽可能地靠近 异类间的点尽可能地远离
Fisherfaces采用LDA(Linear Discriminant Analysis,线性判别分析)实现人脸识别。 其基本原理:在低维表示下,首先将训练集样本集投影到一条直线A上,让投影后的点满足: 同类间的点尽可能地靠近 异类间的点尽可能地远离
代码部分
其实看上面原理那么复杂,但是到了代码部分就很简单了,只是一个借口调用的事儿。下面我只用一个方法来展示
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFontdef cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30):"""向图片中添加中文文本"""if isinstance(img, np.ndarray): # 判断是否OpenCV图片类型img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) # 实现array到image的转换# 创建绘图对象draw = ImageDraw.Draw(img)# 字体的格式 - 需要指定中文字体路径,例如使用系统自带的SimHei.ttf# 如果找不到中文字体,可以下载一个或使用其他中文字体try:fontStyle = ImageFont.truetype("simhei.ttf", textSize, encoding="utf-8")except:# 如果找不到指定字体,使用默认字体fontStyle = ImageFont.load_default()# 绘制文本draw.text(position, text, textColor, font=fontStyle)# 转换回OpenCV格式return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)def image_re(image_path, size=(120, 180)):"""读取并调整图像大小"""img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) # 以灰度模式读取if img is None:print(f"错误: 无法读取图像 {image_path}")return Noneimg = cv2.resize(img, size) # 调整图像大小return img# 主程序
if __name__ == "__main__":# 准备训练数据images = []# 读取并调整图像大小a = cv2.imread('img.png', 0) # flags=0 表示以灰度模式读取a = cv2.resize(a, (120, 180)) # 调整图像大小为120x180像素b = cv2.imread('img_1.png', 0)b = cv2.resize(b, (120, 180))e = cv2.imread('img_7.png', 0)e = cv2.resize(b, (120, 180))c = cv2.imread('img_2.png', 0)c = cv2.resize(c, (120, 180))d = cv2.imread('img_3.png', 0)d = cv2.resize(d, (120, 180))f = cv2.imread('img_8.png', 0)f = cv2.resize(f, (120, 180))g = cv2.imread('img_9.png', 0)g = cv2.resize(g, (120, 180))a1 = cv2.imread('img_11.png', 0)a1 = cv2.resize(a1, (120, 180))a2 = cv2.imread('img_12.png', 0)a2 = cv2.resize(a2, (120, 180))# 将图像添加到列表中images.append(a)images.append(b)# images.append(c)# images.append(d)images.append(e)images.append(f)images.append(g)images.append(c)images.append(d)images.append(a1)images.append(a2)# 对应的标签labels = [0, 0, 0, 0, 0, 1, 1, 0, 0] # 0代表hg,1代表pyy# 创建FisherFace人脸识别器# cv2.face.FisherFaceRecognizer_create([, num_components[, threshold]])# 作用:创建一个FisherFace的人脸特征识别器# num_components: 进行线性判别分析时保留的成分数量。可以采用默认值"0",让函数自动设置合适的成分数量。# threshold: 进行识别时所用的阈值。如果最近的距离比设定的阈值threshold还要大,函数会返回"-1"。recognizer = cv2.face.FisherFaceRecognizer_create(threshold=5000.0)# 使用训练数据(images和labels)来训练识别器recognizer.train(images, np.array(labels))# 读取待识别图像pre_image = image_re('img_13.png') # 读取待识别图像if pre_image is None:print("错误: 无法读取待识别图像")exit(1)# 对预测图像进行人脸识别预测# confidence: 大小介于0到20000,只要低于5000都被认为是可靠的结果。label, confidence = recognizer.predict(pre_image)# 标签到人名的映射字典dic = {0: '爱坤', 1: '良子', -1: "为检索到"}# 输出识别结果print('这人是:', dic[label])print('置信度为:', confidence)# 在图像上标注识别结果并显示result_image = cv2.imread('img_13.png') # 读取彩色图像用于显示if result_image is not None:# 在图像上添加中文文本result_image = cv2AddChineseText(result_image, dic[label], (30, 10), textColor=(255, 0, 0))cv2.imshow('识别结果', result_image)cv2.waitKey(0)cv2.destroyAllWindows()else:print("无法显示结果图像")
这里我使用了蔡徐坤和良子进行训练,找了好几张图片结果预测的还行,也算预测出来了,第一种算法我都没有预测对
结果展示
代码概述
定义了两个函数,一个是因为cv2对中文很不友好。在puttext中不能添加中文,所以这里使用了PIL来添加。然后就是一个添加图片到数列的函数。
然后就是正常的给标签。然后进行训练。得到预测值,预测值会返回预测标签和置信度,一般小于20000就是还好可信。