第十节、人脸识别之特征脸算法
人脸检测是OpenCV的一个很不错的功能,它是人脸识别的基础。什么是人脸识别?其实就是一个程序能够识别出给定图像或者视频中的人脸。实现这一目标的方法之一是用一系列分好类的图像(人脸数据库)来训练,并基于这些图像进行识别。
人脸识别所需要的人脸库可以通过两种方式来获得:自己获得图像或从人脸数据库免费获得可用的人脸图像,互联网上有许多人脸数据库,这里以ORL人脸库(包含40个人,每人10张人脸,共400张人脸)为例,ORL人脸库中每一张图像大小为92x112,我们要想对这些样本进行人脸识别,必须要在包含人脸的样本图像上进行人脸识别。除了要识别ORL人脸库,我们也还想要识别出自己,所以我们还需要准备自己的图像。
一 生成自己的人脸图像
我们通过摄像头采集自己的人脸,大约10张图像就可以,我们需要把图像调整为92x112的大小,并且保存到一个指定文件夹,文件名后缀为.pgm。代码如下:
#1、生成自己人脸识别数据 def generator(data): ''' 生成的图片满足以下条件 1、图像是灰度格式,后缀为.pgm 2、图像大小要一样 params: data:指定生成的人脸数据的保存路径 ''' ''' 打开摄像头,读取帧,检测帧中的人脸,并剪切,缩放 ''' name = input('my name:') #如果路径存在则删除 path = os.path.join(data,name) if os.path.isdir(path): #os.remove(path) #删除文件 #os.removedirs(path) #删除空文件夹 shutil.rmtree(path) #递归删除文件夹 #创建文件夹 os.mkdir(path) #创建一个级联分类器 加载一个 .xml 分类器文件. 它既可以是Haar特征也可以是LBP特征的分类器. face_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_frontalface_default.xml') #打开摄像头 camera = cv2.VideoCapture(0) cv2.namedWindow('Dynamic') #计数 count = 1 while(True): #读取一帧图像 ret,frame = camera.read() #判断图片读取成功? if ret: gray_img = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) #人脸检测 faces = face_cascade.detectMultiScale(gray_img,1.3,5) for (x,y,w,h) in faces: #在原图像上绘制矩形 cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2) #调整图像大小 和ORL人脸库图像一样大小 f = cv2.resize(frame[y:y+h,x:x+w],(92,112)) #保存人脸 cv2.imwrite('%s/%s.pgm'%(path,str(count)),f) count += 1 cv2.imshow('Dynamic',frame) #如果按下q键则退出 if cv2.waitKey(100) & 0xff == ord('q') : break camera.release() cv2.destroyAllWindows()
程序运行后,我们需要输入自己的姓名,这里我输入zy,并在data路径下生成了一个zy文件夹,下面保存着采集到的图像:
二 人脸识别(OpenCV)
OpenCV 3有三种人脸识别的方法,它们分别基于不同的三种算法,Eigenfaces,Fisherfaces和Local Binary Pattern Histogram。
这些方法都有一个类似的过程,即都使用分好类的训练数据集来进行训练,对图像或视频中检测到的人脸进行分析,并从两方面来确定:是否识别到目标;目标真正被识别到的置信度的衡量,这也称为置信度评分,在实际应用中可以通过设置阈值来进行筛选,置信度高于该阈值的人脸将会被丢弃。
这里我们主要来介绍一下利用特征脸进行人脸识别的方法,特征脸法,本质上其实就是PCA降维,这种算法的基本思路是,把二维的图像先灰度化,转化为一通道的图像,之后再把它首尾相接转化为一个列向量,假设图像大小是20*20的,那么这个向量就是400维,理论上讲组织成一个向量,就可以应用任何机器学习算法了,但是维度太高算法复杂度也会随之升高,所以需要使用PCA算法降维,然后使用简单排序或者KNN都可以。
2.1 准备数据
我们先来准备训练所需要的数据,这里我们需要的数据有训练的图像,每个图像对应的标签以及标签对应的真实姓名。
#2、读取ORL人脸数据库 准备训练数据 def LoadImages(data): ''' 加载数据集 params: data:训练集数据所在的目录,要求数据尺寸大小一样 ret: images:[m,height,width] m为样本数,height为高,width为宽 names:名字的集合 labels:标签 ''' images = [] labels = [] names = [] label = 0 #过滤所有的文件夹 for subDirname in os.listdir(data): subjectPath = os.path.join(data,subDirname) if os.path.isdir(subjectPath): #每一个文件夹下存放着一个人的照片 names.append(subDirname) for fileName in os.listdir(subjectPath): imgPath = os.path.join(subjectPath,fileName) img = cv2.imread(imgPath,cv2.IMREAD_GRAYSCALE) images.append(img) labels.append(label) label += 1 images = np.asarray(images) labels = np.asarray(labels) return images,labels,names
2.2 人脸识别
有了训练数据之后,我们就可以直接调用OpenCV 3的人脸识别库进行训练,训练好之后,就可以进行识别:
def FaceRec(data): #加载训练数据 X,y,names=LoadImages('./face') model = cv2.face.EigenFaceRecognizer_create() model.train(X,y) #创建一个级联分类器 加载一个 .xml 分类器文件. 它既可以是Haar特征也可以是LBP特征的分类器. face_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_frontalface_default.xml') #打开摄像头 camera = cv2.VideoCapture(0) cv2.namedWindow('Dynamic') while(True): #读取一帧图像 ret,frame = camera.read() #判断图片读取成功? if ret: gray_img = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) #人脸检测 faces = face_cascade.detectMultiScale(gray_img,1.3,5) for (x,y,w,h) in faces: #在原图像上绘制矩形 frame = cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2) roi_gray = gray_img[y:y+h,x:x+w] try: #宽92 高112 roi_gray = cv2.resize(roi_gray,(92,112),interpolation=cv2.INTER_LINEAR) params = model.predict(roi_gray) print('Label:%s,confidence:%.2f'%(params[0],params[1])) cv2.putText(frame,names[params[0]],(x,y-20),cv2.FONT_HERSHEY_SIMPLEX,1,255,2) except: continue cv2.imshow('Dynamic',frame) #如果按下q键则退出 if cv2.waitKey(100) & 0xff == ord('q') : break camera.release() cv2.destroyAllWindows()
这里我们cv2.face.EigenFaceRecognizer_create()创建人脸识别模型,通过图像数组和对应标签数组来训练模型,EigenFaceRecognizer_create()函数有两个可以设置的重要参数:第一个是想要保留的主成分数目,第二个是指定的置信度阈值,这是一个浮点数。
接下来,重复与人脸检测操作类似的过程。通过在检测到的人脸上进行人脸识别,注意这里有两个步骤:
- 1、将检测到人脸调整为指定的大小92x112,即与训练集图像尺寸一样;
- 2、调用prdict()函数进行预测,该函数返回有两个元素的数组,第一个元素是所识别个体的标签,第二个是置信度评分,用来衡量所识别人脸与原模型的差距,0表示完全匹配。
注意:Eigenfaces/Fisherfaces和LBPH的置信度评分值完全不同,Eigenfaces和Fisherfaces将产生0到20000的值,而任意低于4000到5000的评分都是相当可靠的识别。LBPH有着类似的工作方式,但是一个好的识别参考值要低于50,任意高于80的参数值都被认为是低的置信度评分。
源代码:
# -*- coding: utf-8 -*- """ Created on Thu Aug 16 19:41:19 2018 @author: lenovo """ ''' 调用opencv库实现人脸识别 ''' import numpy as np import cv2 import os import shutil #读取pgm图像,并显示 def ShowPgm(filepath): cv2.namedWindow('pgm') img = cv2.imread(filepath) cv2.imshow('pgm',img) print(img.shape) cv2.waitKey(0) cv2.destroyAllWindows() #1、生成自己人脸识别数据 def generator(data): ''' 生成的图片满足以下条件 1、图像是灰度格式,后缀为.pgm 2、图像大小要一样 params: data:指定生成的人脸数据的保存路径 ''' ''' 打开摄像头,读取帧,检测帧中的人脸,并剪切,缩放 ''' name = input('my name:') #如果路径存在则删除 path = os.path.join(data,name) if os.path.isdir(path): #os.remove(path) #删除文件 #os.removedirs(path) #删除空文件夹 shutil.rmtree(path) #递归删除文件夹 #创建文件夹 os.mkdir(path) #创建一个级联分类器 加载一个 .xml 分类器文件. 它既可以是Haar特征也可以是LBP特征的分类器. face_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_frontalface_default.xml') #打开摄像头 camera = cv2.VideoCapture(0) cv2.namedWindow('Dynamic') #计数 count = 1 while(True): #读取一帧图像 ret,frame = camera.read() #判断图片读取成功? if ret: gray_img = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) #人脸检测 faces = face_cascade.detectMultiScale(gray_img,1.3,5) for (x,y,w,h) in faces: #在原图像上绘制矩形 cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2) #调整图像大小 和ORL人脸库图像一样大小 f = cv2.resize(frame[y:y+h,x:x+w],(92,112)) #保存人脸 cv2.imwrite('%s/%s.pgm'%(path,str(count)),f) count += 1 cv2.imshow('Dynamic',frame) #如果按下q键则退出 if cv2.waitKey(100) & 0xff == ord('q') : break camera.release() cv2.destroyAllWindows() #2、读取ORL人脸数据库 准备训练数据 def LoadImages(data): ''' 加载数据集 params: data:训练集数据所在的目录,要求数据尺寸大小一样 ret: images:[m,height,width] m为样本数,height为高,width为宽 names:名字的集合 labels:标签 ''' images = [] labels = [] names = [] label = 0 #过滤所有的文件夹 for subDirname in os.listdir(data): subjectPath = os.path.join(data,subDirname) if os.path.isdir(subjectPath): #每一个文件夹下存放着一个人的照片 names.append(subDirname) for fileName in os.listdir(subjectPath): imgPath = os.path.join(subjectPath,fileName) img = cv2.imread(imgPath,cv2.IMREAD_GRAYSCALE) images.append(img) labels.append(label) label += 1 images = np.asarray(images) labels = np.asarray(labels) return images,labels,names def FaceRec(data): #加载训练数据 X,y,names=LoadImages('./face') model = cv2.face.EigenFaceRecognizer_create() model.train(X,y) #创建一个级联分类器 加载一个 .xml 分类器文件. 它既可以是Haar特征也可以是LBP特征的分类器. face_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_frontalface_default.xml') #打开摄像头 camera = cv2.VideoCapture(0) cv2.namedWindow('Dynamic') while(True): #读取一帧图像 ret,frame = camera.read() #判断图片读取成功? if ret: gray_img = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) #人脸检测 faces = face_cascade.detectMultiScale(gray_img,1.3,5) for (x,y,w,h) in faces: #在原图像上绘制矩形 frame = cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2) roi_gray = gray_img[y:y+h,x:x+w] try: #宽92 高112 roi_gray = cv2.resize(roi_gray,(92,112),interpolation=cv2.INTER_LINEAR) params = model.predict(roi_gray) print('Label:%s,confidence:%.2f'%(params[0],params[1])) cv2.putText(frame,names[params[0]],(x,y-20),cv2.FONT_HERSHEY_SIMPLEX,1,255,2) except: continue cv2.imshow('Dynamic',frame) #如果按下q键则退出 if cv2.waitKey(100) & 0xff == ord('q') : break camera.release() cv2.destroyAllWindows() if __name__=='__main__': #ShowPgm('./face/s1/1.pgm') data = './face' #生成自己的人脸数据 #generator(data) FaceRec(data)
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Linux系统下SQL Server数据库镜像配置全流程详解
· 现代计算机视觉入门之:什么是视频
· 你所不知道的 C/C++ 宏知识
· 不到万不得已,千万不要去外包
· C# WebAPI 插件热插拔(持续更新中)
· 会议真的有必要吗?我们产品开发9年了,但从来没开过会
· 【译】我们最喜欢的2024年的 Visual Studio 新功能
· 如何打造一个高并发系统?