基于opencv和pillow实现人脸识别系统(附demo)
作者:爱编程的小段 发布时间:2023-04-06 10:28:53
本文不涉及分类器、训练识别器等算法原理,仅包含对其应用(未来我也会写自己对机器学习算法原理的一些观点和了解)
首先我们需要知道的是利用现有框架做一个人脸识别系统并不难,然后就开始我们的系统开发吧。
我们的系统主要分为三个部分,然后我还会提出对补获图片不能添加中文的解决方案。我们需要完成的任务:1.人脸检测和数据收集2.训练识别器3.人脸识别和显示
在读此篇文章之前我相信你已经做了python环境部署和opencv模块的下载安装工作,现在我们还需要的模块是pillow(树莓派默认带有此模块,但如果你用的是win系统可能还需要另外安装,在终端输入pip install pillow即可),和opencv-contrib模块,cv2的face模块包含在内(当然我的Linux系统的树莓派貌似仍然默认包含了此模块,所以如果你是用的pc可能需要另外下载),以及最基本的numpy模块。
在开始写代码之前我们首先需要在当前运行目录中添加两个文件夹,dataset用于存放捕获到的人脸图像,方便后面训练识别器,trainer文件夹则存放了训练结果
一。人脸检测和数据收集
#数据采集
cam = cv2.VideoCapture(0)#补获图片
cam.set(3, 640) # set video width
cam.set(4, 480) # set video height
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')#导入分类器
# For each person, enter one numeric face id
face_id = input('\n 输入用户id')
print("\n 数据采集中,请正视摄像头轻微扭转")
# Initialize individual sampling face count
count = 0
while(True):
ret, img = cam.read()#ret为是否成功读取,是一个布尔值
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#转化为灰度图
faces = face_detector.detectMultiScale(gray, 1.3, 5,minSize=(100,100))
for (x,y,w,h) in faces:#此处faces是一个array数组或空的元组,原因我后面会分析
cv2.rectangle(img, (x,y), (x+w,y+h), (255,0,0), 2)
count += 1
# Save the captured image into the datasets folder
cv2.imwrite("dataset/User." + str(face_id) + '.' + str(count) + ".jpg", gray[y:y+h,x:x+w])
cv2.imshow('image', img)
k = cv2.waitKey(100) & 0xff # Press 'ESC' for exiting video
if k == 27:
break
elif count >= 10: # Take 10 face sample and stop video
break
# Do a bit of cleanup
print("\n [INFO] Exiting Program and cleanup stuff")
cam.release()
cv2.destroyAllWindows()
在这一部分中我们完成了人脸的补获,并将其保存在了我们建立的dataset文件夹,并将每一个人的数据用特定的id表述,这样我们就能训练能识别不同人脸的识别器。cam.set这一步中第二个参数是图像的分辨率,640×480是opencv的默认分辨率,但其仍支持800×600且最大支持1280乘1024像素,即使你的摄像头最大允许分辨率远大于这个值,opencv貌似仍不会允许你使用。之后就是haar级联分类器的导入,在配置过程中,我们已经下载了opencv自带的分类器,你只需要在文件管理器中查找haarcascade_frontalface_default.xml这个文件即可,在这个文件所在的文件夹中有许多分类器,当然如果你要识别例如苹果香蕉等物体你可能需要训练新的分类器(这也很容易做到),本文讨论的是人脸识别,因此这里不再赘述,你可以选择用其绝对路径导入,当然你也可以像我一样将其复制到你当前目录中。然后进入循环,图片的读取->转灰度图,然后是使用你已经导入的分类器识别人脸并将其用方框标出,然后将方框内的图片储存入dataset文件夹中。值得一提的是,因为分类器的算法是很慢的,所以分类器本身就有减帧处理(即使这样我的树莓派带人脸识别系统仍然很吃力),所以faces应该是大部分时间都是空的元组,小部分时间是读取到的array数组,因此你需要特别注意缩进问题,不要让分类器本身的减帧影响你视频读取并显示的帧数。
二.训练识别器
import cv2
#训练器
import numpy as np
from PIL import Image
import os
# Path for face image database
path = 'dataset'
recognizer = cv2.face.LBPHFaceRecognizer_create()#识别器的导入
detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
# function to get the images and label data
def getImagesAndLabels(path):
imagePaths = [os.path.join(path,f) for f in os.listdir(path)]#在这里os模块可以帮助我们很好的建立路径,建议可以先查看一下相关函数的使用方法。
faceSamples=[]
ids = []
for imagePath in imagePaths:
PIL_img = Image.open(imagePath).convert('L') #转化为灰度图
img_numpy = np.array(PIL_img,'uint8')#转化为数组
id = int(os.path.split(imagePath)[-1].split(".")[1])
faces = detector.detectMultiScale(img_numpy)
for (x,y,w,h) in faces:
faceSamples.append(img_numpy[y:y+h,x:x+w])
ids.append(id)
return faceSamples,ids
print ("\n 训练数据中,请稍后")
faces,ids = getImagesAndLabels(path)
recognizer.train(faces, np.array(ids))
# Save the model into trainer/trainer.yml
recognizer.write('trainer/trainer.yml') # recognizer.save() worked on Mac, but not on Pi
# Print the numer of faces trained and end program
print("\n {0} 张脸训练完毕. 程序关闭".format(len(np.unique(ids))))
在这一步我们需要对识别器按照不同id分别训练并保存结果,并将结果汇总写入trainer文件夹中命名为trainer.yml。这个文件里就是训练好的识别器。
三.人脸识别和显示
# -*- coding: UTF-8 -*-
#识别器
import cv2
import numpy as np
import os
from PIL import Image, ImageFont, ImageDraw
path_to_ttf = 'C:\Windows\Fonts\Microsoft YaHei UI\msyh.ttc'#ttc文件是支持汉语的字体,稍后我会说明。
font1= ImageFont.truetype(path_to_ttf, size=20)
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('trainer/trainer.yml')#读取识别器
cascadePath = "haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascadePath);
font = cv2.FONT_HERSHEY_SIMPLEX
#iniciate id counter
id = 0
# names related to ids: example ==> Marcelo: id=1, etc
names = ['None', '段林晨', 'Paula', 'Ilza', 'Z', 'W']#因为我们不会在人脸识别时只显示你的代号而是要显示你的具体信息。
cam = cv2.VideoCapture(0)
cam.set(3, 640) # set video widht
cam.set(4, 480) # set video height
#最小识别的脸的大小,在识别过程中,我们不会捕获到距离你很远的街上路人的信息,这会导致很多问题,因此我们只需要识别想参与识别的人,而设置最小人脸识别大小可以规避这一点
minW = 0.1*cam.get(3)
minH = 0.1*cam.get(4)
while True:
ret, img =cam.read()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor = 1.2,
minNeighbors = 5,
minSize = (int(minW), int(minH)),
)#相关参数设置可以自行搜索
for(x,y,w,h) in faces:
cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
id, confidence = recognizer.predict(gray[y:y+h,x:x+w])
# Check if confidence is less them 100 ==> "0" is perfect match
if (confidence < 100):
id = names[id]
confidence = " {0}%".format(round(100 - confidence))#confidence是置信度指数,等于100-概率,相信大家的概率统计一定比我优秀
else:
id = "未识别"
confidence = " {0}%".format(round(100 - confidence))
img=Image.fromarray(img)
draw = ImageDraw.Draw(img)
draw.text(xy=(x+5,y-5), text=str(id), font=font1,fill=(255,255,255))
img=np.array(img)
cv2.putText(img, str(confidence), (x+5,y+h-5), font, 1, (255,255,0), 1)
cv2.imshow('camera',img)
k = cv2.waitKey(10) & 0xff # Press 'ESC' for exiting video
if k == 27:
break
# Do a bit of cleanup
print("\n [INFO] Exiting Program and cleanup stuff")
cam.release()
cv2.destroyAllWindows()
在这一步中,很遗憾的是cv2.putText函数并不支持汉语的应用,即你不能通过这个函数将汉语姓名显示在视频中,虽然你可能会有英文名或干脆用汉语拼音,但这个问题我们必须要解决。因此我们在这里引入了pillow模块,我们只需要使用img.draw功能在图片上先打出你的姓名,再进行cv2.putText函数就能很好的解决这个问题,但是比较麻烦的是这两个函数涉及到的图片类型是不一样的,因此我在代码中对img和array图像进行了转换,最终完成了人脸识别系统。
来源:https://blog.csdn.net/qq_45694203/article/details/112914948


猜你喜欢
- 概要 简单介绍几种用于判断numpy数组是否全
- 不知道大家有没有遇到这样的情况,比如视频合并时文件名没有按照正常顺序排列,像这样 可见,文件名排序是乱的。这个样子合并
- 本文实例总结了Python实现string字符串连接的方法。分享给大家供大家参考,具体如下:以下基于python 2.7版本,代码片段真实有
- 数据安全是任何数据服务解决方案中的一个关键要求,而Windows Server 2008和SQL Server 2008结合起来,通过一个基
- Python中除了字典,列表,元组还有一个非常好用的数据结构,那就是set了,灵活的运用set可以减去不少的操作(虽然set可以用列表代替)
- 本文实例讲述了flask框架视图函数用法。分享给大家供大家参考,具体如下:flask框架 视图函数当中 各种实用情况简单配置1 建立连接2
- 如下所示:<!doctype html><html lang="en"> <head>
- 本文实例讲述了Python实现计算圆周率π的值到任意位的方法。分享给大家供大家参考,具体如下:一、需求分析输入想要计算到小数点后的位数,计算
- ########################## # # # 为了避免截断中文字符 # # 文件要求是 unicode 编码 # # t
- 第一种方法:在php.ini文件里改变display_errors和error_reporting的值,没有的直接加上; 第一处修改; di
- 本文实例为大家分享了Python使用tkinter实现小时钟效果的具体代码,供大家参考,具体内容如下自己又调试了一下,分享一下# codin
- 一维列表的初始化:初始一个长度为5的列表方式1:a = [0]*5# [0, 0, 0, 0, 0]方式2:a = [0 for _ in
- 概述在本文中,我们将以深度库即 Mediapipe为基础库,以及其他计算机视觉预处理的CV2库来制作手部地标检测模型。市场上有很多关于这种问
- 两段使用键盘的上下键进行选择的代码:<Script Language="JScript"> &
- 前言第一次尝试用Pyinstaller打包Pytorch,碰见了很多问题,耗费了许多时间!想把这个过程中碰到的问题与解决方法记录一下,方便后
- 博主最近需要做一个物流信息查询,就去网上搜索一个快递鸟的API接口,返回值是以JSON格式,只需要返回是转成数组就能轻松实现各种实例了。下图
- 还是先上代码吧 ,可以先看 SQL语句去掉重复记录,获取重复记录ALTER procedure [dbo].[PROC_ITEMMASTER
- 一 引入jwtjwt用户身份验证go get github.com/dgrijalva/jwt-go二 框架中引入jwtimport (&q
- 如下所示:import cv2import mathimport numpy as npdef move(img): height, wid
- 什么是插槽?我们知道在Vue中 Child 组件的标签 的中间是不可以包着什么的 。可是往往在很多时候我们在使用组件的时候总想在组件间外面自