百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Python+OpenCV人脸识别(基于LBPH+防照片识别+警报)

off999 2024-10-20 08:09 34 浏览 0 评论

  • 目录

废话

1.环境配置(jupyter notebook python 3.6.5)

2.训练集准备

3.代码思路(艹图)

4.人脸识别源码

5.参考文章

6.可能遇到的问题


废话

嗯,开局说点废话,之前用stm32和esp8266改装了下宿舍门,但终究觉得没人脸识别来得舒服,所以就有了这篇文章

1.环境配置(jupyter notebook python 3.6.5)

我这里用的是python3.6,如果你想搭建一个3.6的环境又不想影响原有的,可以用小黑窗(Anaconda Prompt)搭建一个虚拟环境(虚拟环境是一个独立的空间不会影响外界,也不会受外界影响,适合应对不同版本python的需求)

如何搭建虚拟环境可以看看这篇文,简单粗暴

当你搭建好虚拟环境后,第三方库的安装也要安在虚拟环境里,那么如何切换到虚拟环境里呢

打开小黑窗 activate 虚拟环境名字就可以激活了效果如下:


看到小括号就说明已经切换到虚拟环境里了

然后就可以安装所需的第三方库了,eg.Opencv,scipy,request,dlib,安装方法如下:

1)OpenCV

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-contrib-python==3.4.2.16
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python==3.4.2.16

2)scipy

pip install scipy

3) request

pip install request

4) dlib

dlib库的安装比较麻烦,你得先找到对应版本,因为不同python版本对应不同dlib

如果你跟我一样是3.6,那装19.7就行

缺版本或找不到对应版本可以留言

2.训练集准备

这个训练集捏,是借助recognizer.train得到的.yml文件,所以精度没特别高,但是拿来玩玩门锁 还是够用,追求精度可以走深度学习

代码如下:

1)第一步准备照片(即你的人脸像),以“序号.名称”命名,例如“1.xx"这是为了方便切片和保存(即我们可以通过切片将每张照片的脸部特征,序号,名称一一对应)记得你照片的存放路径

2)第二步准备人脸数据集haarcascade_frontalface_alt2.xml,这个是opencv自带的用于检测人脸(注意是检测人脸不是识别人脸)这种做法我觉得有点像RIO ,就是我们在一张图片中匹配人像特征不是从角落开始,而是定位人脸,然后规划一个区域,在区域内进行匹配,这样节省很多时间

3)第三步,跑代码就完事了,然后你会在你指定的文件夹里面找到yml文件,这就是你的训练集

import osimport sysfrom PIL import Imageimport numpy as npimport cv2
def getImageAndLabels(path):    #建两个空列表后续存储数据    facesSamples=[]    ids=[]    imagePaths=[os.path.join(path,f) for f in os.listdir(path)]    #检测人脸    face_detector = cv2.CascadeClassifier('E:\jupyter_notebook\practice\haarcascades\haarcascade_frontalface_alt2.xml')    #打印数组imagePaths    print('路径:',imagePaths)    #遍历列表中的图片    for imagePath in imagePaths:        #打开图片,灰度        PIL_img=Image.open(imagePath).convert('L')        #此时获取的是整张图片的数组        img_numpy=np.array(PIL_img,'uint8')        #获取图片人脸特征,相当于rio        faces = face_detector.detectMultiScale(img_numpy)        #将文件名前的名字转化为ID并记录下来        str_id = os.path.split(imagePath)[1].split('.')[0]        id = int(str_id)        #id = os.path.split(imagePath)[1].split('.')[0]        #预防检测到无面容照片        for x,y,w,h in faces:            #把ID写进ids列表中            ids.append(id)            #把所画的方框写进facesSamples列表中            facesSamples.append(img_numpy[y:y+h,x:x+w])        #打印脸部特征和id          print('id:', id)    print('fs:', facesSamples)    return facesSamples,ids
if __name__ == '__main__':    #图片路径    path='E:/face_dormitory/train'    #获取图像数组和id标签数组和姓名    faces,ids=getImageAndLabels(path)    #获取训练对象    recognizer=cv2.face.LBPHFaceRecognizer_create()    recognizer.train(faces,np.array(ids))    #保存文件    recognizer.write('E:/face_dormitory/opencv/trainer/trainer_xx.yml')

3.代码思路(艹图)

4.人脸识别源码

1)引入库

import cv2import numpy as npimport osimport urllibimport urllib.requestimport hashlibfrom scipy.spatial import distance as distfrom collections import OrderedDictimport argparseimport timeimport dlib

2)加载训练集(这里shape_predictor_68_face_landmarks是用于眨眼检测的)

#加载训练数据集文件recogizer=cv2.face.LBPHFaceRecognizer_create()recogizer.read('E:/face_dormitory/opencv/trainer/trainer_xx.yml')names=[] #建个空id列表warningtime = 0predictor = dlib.shape_predictor('E:/face_dormitory/opencv/shape_predictor_68_face_landmarks.dat')

3)邮件函数(即识别出陌生人或可疑人用于发送抓拍照片的)

import smtplibfrom PIL import Imageimport email  # 文件名不可以和引入的库同名from email.mime.image import MIMEImage  # 图片类型邮件from email.mime.text import MIMEText  # MIME 多用于邮件扩充协议from email.mime.multipart import MIMEMultipart  # 创建附件类型 HOST = 'smtp.qq.com'  # 调用的邮箱借借口SUBJECT = 'Warning!!!'  # 设置邮件标题FROM = '1xxxxxxxxx@qq.com'  # 发件人的邮箱需先设置开启smtp协议#TO = '1xxxxxxxxxxx@qq.com'  # 设置收件人的邮箱(可以一次发给多个人,用逗号分隔)TO = 'xxxxxxxxxx@qq.com'  # 设置收件人的邮箱(可以一次发给多个人,用逗号分隔)message = MIMEMultipart('related')  # 邮件信息,内容为空  #相当于信封##related表示使用内嵌资源的形式,将邮件发送给对方 def sendmail(HOST, SUBJECT,FROM,TO,message):     # ===========发送信息内容=============    message_html = MIMEText('<h1 style="color:red;font-size:100px">Warning!!!</h1><img src="cid:small">', 'html', 'utf-8')    message.attach(message_html)     # ===========发送图片-=============    message_image0 = MIMEText(open('E:/face_dormitory/unidentified/0.jpg', 'rb').read(), 'base64', 'utf-8')    message_image0['Content-disposition'] = 'attachment;filename="Suspicious people.jpg"'# 设置图片在附件当中的名字    message_image1 = MIMEText(open('E:/face_dormitory/unidentified/1.jpg', 'rb').read(), 'base64', 'utf-8')    message_image1['Content-disposition'] = 'attachment;filename="Suspicious people.jpg"'# 设置图片在附件当中的名字    message.attach(message_image0)# 添加图片文件到邮件-附件中去    message.attach(message_image1)# 添加图片文件到邮件-附件中去    '''    path='E:/face_dormitory/unidentified'    imagePaths=[os.path.join(path,f) for f in os.listdir(path)]    for imagePath in imagePaths:        PIL_img=Image.open(imagePath,'utf-8')        PIL_img['Content-disposition'] = 'attachment;filename="Suspicious people.jpg"'        message.attach(PIL_img)     '''       # ===========删除缓冲图片-=============    #os.remove('E:/face_dormitory/unidentified/0.jpg')    #os.remove('E:/face_dormitory/unidentified/1.jpg')    # ===========发送excel-附件=============    #message_xlsx = MIMEText(open('email_demo.xlsx', 'rb').read(), 'base64', 'utf-8')# 将xlsx文件作为内容发送到对方的邮箱读取excel,rb形式读取,对于MIMEText()来说默认的编码形式是base64 对于二进制文件来说没有设置base64,会出现乱码    #message_xlsx['Content-Disposition'] = 'attachment;filename="email_demo_change.xlsx"'# 设置文件在附件当中的名字    #message.attach(message_xlsx)# 添加excel文件到邮件-附件中去     # ===========配置相关-=============    message['From'] = FROM # 设置邮件发件人    message['TO'] = TO # 设置邮件收件人    message['Subject'] = SUBJECT # 设置邮件标题    email_client = smtplib.SMTP_SSL()# 获取传输协议    email_client.connect(HOST, '465')# 设置发送域名,端口465    result = email_client.login(FROM, 'xxxxxxx')  # qq授权码    print('登录结果', result)     # ===========操作=============    email_client.sendmail(from_addr=FROM, to_addrs=TO.split(','), msg=message.as_string()) #发送邮件指令    email_client.close()# 关闭邮件发送客户端

写邮件函数我是借鉴这个大佬的,站在巨人肩膀上嘛,总不能什么都靠自己来

4)防照片检测(即眨眼检测)这个也可以用于疲劳检测

详见:i·bug - resources - Facial point annotations

FACIAL_LANDMARKS_68_IDXS = OrderedDict([    ("mouth", (48, 68)),    ("right_eyebrow", (17, 22)),    ("left_eyebrow", (22, 27)),    ("right_eye", (36, 42)),    ("left_eye", (42, 48)),    ("nose", (27, 36)),    ("jaw", (0, 17))])
def eye_aspect_ratio(eye):    # 计算距离,竖直的    A = dist.euclidean(eye[1], eye[5])    B = dist.euclidean(eye[2], eye[4])    # 计算距离,水平的    C = dist.euclidean(eye[0], eye[3])    # ear值    ear = (A + B) / (2.0 * C)    return ear
def shape_to_np(shape, dtype="int"):    # 创建68*2    coords = np.zeros((shape.num_parts, 2), dtype=dtype)    # 遍历每一个关键点    # 得到坐标    for i in range(0, shape.num_parts):        coords[i] = (shape.part(i).x, shape.part(i).y)    return coords
def pervent_to_photo():        # 设置判断参数    EYE_AR_THRESH = 0.3    EYE_AR_CONSEC_FRAMES = 3     # 初始化计数器    COUNTER = 0    TOTAL = 0     # 检测与定位工具    print("loading facial landmark predictor...")    detector = dlib.get_frontal_face_detector()    #predictor = dlib.shape_predictor('E:/face_dormitory/opencv/shape_predictor_68_face_landmarks.dat')     # 分别取两个眼睛区域    (lStart, lEnd) = FACIAL_LANDMARKS_68_IDXS["left_eye"]    (rStart, rEnd) = FACIAL_LANDMARKS_68_IDXS["right_eye"]     # 读取视频    print("starting video stream thread...")    vs = cv2.VideoCapture(0)    time.sleep(1.0)     # 遍历每一帧    while True:        # 预处理        frame = vs.read()[1]        if frame is None:            break        (h, w) = frame.shape[:2]        width=1200        r = width / float(w)        dim = (width, int(h * r))        frame = cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)         # 检测人脸        rects = detector(gray, 0)         # 遍历每一个检测到的人脸        for rect in rects:            # 获取坐标            shape = predictor(gray, rect)            shape = shape_to_np(shape)             # 分别计算ear值            leftEye = shape[lStart:lEnd]            rightEye = shape[rStart:rEnd]            leftEAR = eye_aspect_ratio(leftEye)            rightEAR = eye_aspect_ratio(rightEye)             # 算一个平均的            ear = (leftEAR + rightEAR) / 2.0             # 绘制眼睛区域            leftEyeHull = cv2.convexHull(leftEye)            rightEyeHull = cv2.convexHull(rightEye)            cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1)            cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1)             # 检查是否满足阈值            if ear < EYE_AR_THRESH:                COUNTER += 1             else:                # 如果连续几帧都是闭眼的,总数算一次                if COUNTER >= EYE_AR_CONSEC_FRAMES:                    TOTAL += 1                 # 重置                COUNTER = 0             # 显示            cv2.putText(frame, "Blinks: {}".format(TOTAL), (10, 30),                cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)            cv2.putText(frame, "EAR: {:.2f}".format(ear), (300, 30),                cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)         cv2.imshow("Frame", frame)                #眨眼两次则判断不是照片        if TOTAL >= 2:            cv2.imwrite(r"E:/face_dormitory/unidentified/"+"1.jpg",frame) #抓拍            break                    #空格退出        if ord(' ') == cv2.waitKey(10):            break     #vs.release()    cv2.destroyAllWindows()

5)人脸检测函数

#准备识别的图片def face_detect_demo(img):    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度    face_detector=cv2.CascadeClassifier('E:\jupyter_notebook\practice\haarcascades\haarcascade_frontalface_alt2.xml') #加入数据集    face=face_detector.detectMultiScale(gray,1.1,5,cv2.CASCADE_SCALE_IMAGE,(100,100),(300,300)) #范围在100*100~300*300判断为脸    for x,y,w,h in face:        cv2.rectangle(img,(x,y),(x+w,y+h),color=(0,0,255),thickness=2)        cv2.circle(img,center=(x+w//2,y+h//2),radius=w//2,color=(0,255,0),thickness=1)        # 人脸识别        ids, confidence = recogizer.predict(gray[y:y + h, x:x + w])        #置信评分 confidence 越大越不可信        if confidence > 50:            global warningtime            global num            warningtime += 1            if warningtime > 100:                #cv2.imwrite(r"E:/face_dormitory/unidentified/"+str(num)+".jpg",frame) #抓拍                cv2.imwrite(r"E:/face_dormitory/unidentified/"+"0.jpg",frame) #抓拍                time.sleep(0.1)                sendmail(HOST=HOST, SUBJECT=SUBJECT,FROM=FROM,TO=TO,message=message)                print('ddddddddddd')                #num += 1                warningtime = 0            cv2.putText(img, 'unidentified', (x + 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1)        else:            cv2.putText(img,str(names[ids-1]), (x + 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1)    cv2.imshow('result',img)
#取名函数,切片取名,即照片名为1.cj.jpg,取名后就为cjdef name():    #相册路径    path = 'E:/face_dormitory/train'    #循环读图    imagePaths=[os.path.join(path,f) for f in os.listdir(path)]    for imagePath in imagePaths:        #切名字        name = str(os.path.split(imagePath)[1].split('.',2)[1])        names.append(name)

6)主函数

#防照片识别pervent_to_photo() #打开摄像头,0是本地默认,1是外用,我把本地关了把外用开着所以直接0cap=cv2.VideoCapture(0)name()while True:    flag,frame=cap.read()    if not flag:        break    face_detect_demo(frame)    #空格退出    if ord(' ') == cv2.waitKey(10):        breakcv2.destroyAllWindows()cap.release() ?

5.参考文章

感谢大佬1

感谢大佬2

感谢大佬3

6.可能遇到的问题

1.如果你搭建了虚拟环境且里面安装了opencv,但是再引用的时候报错没装库,看看有没有将虚拟环境导入kernel

2.如果你发现我的逻辑有问题,相信你自己,错的肯定是我,请务必怼我,毕竟有探讨才有完善,我也是个小菜鸡

3.如果出现”No module named XXX“,说明安装差库了,请跑到虚拟环境里去安装,虚拟环境是独立的,你之前安装了什么都跟虚拟环境无关

相关推荐

面试官:来,讲一下枚举类型在开发时中实际应用场景!

一.基本介绍枚举是JDK1.5新增的数据类型,使用枚举我们可以很好的描述一些特定的业务场景,比如一年中的春、夏、秋、冬,还有每周的周一到周天,还有各种颜色,以及可以用它来描述一些状态信息,比如错...

一日一技:11个基本Python技巧和窍门

1.两个数字的交换.x,y=10,20print(x,y)x,y=y,xprint(x,y)输出:102020102.Python字符串取反a="Ge...

Python Enum 技巧,让代码更简洁、更安全、更易维护

如果你是一名Python开发人员,你很可能使用过enum.Enum来创建可读性和可维护性代码。今天发现一个强大的技巧,可以让Enum的境界更进一层,这个技巧不仅能提高可读性,还能以最小的代价增...

Python元组编程指导教程(python元组的概念)

1.元组基础概念1.1什么是元组元组(Tuple)是Python中一种不可变的序列类型,用于存储多个有序的元素。元组与列表(list)类似,但元组一旦创建就不能修改(不可变),这使得元组在某些场景...

你可能不知道的实用 Python 功能(python有哪些用)

1.超越文件处理的内容管理器大多数开发人员都熟悉使用with语句进行文件操作:withopen('file.txt','r')asfile:co...

Python 2至3.13新特性总结(python 3.10新特性)

以下是Python2到Python3.13的主要新特性总结,按版本分类整理:Python2到Python3的重大变化Python3是一个不向后兼容的版本,主要改进包括:pri...

Python中for循环访问索引值的方法

技术背景在Python编程中,我们经常需要在循环中访问元素的索引值。例如,在处理列表、元组等可迭代对象时,除了要获取元素本身,还需要知道元素的位置。Python提供了多种方式来实现这一需求,下面将详细...

Python enumerate核心应用解析:索引遍历的高效实践方案

喜欢的条友记得关注、点赞、转发、收藏,你们的支持就是我最大的动力源泉。根据GitHub代码分析统计,使用enumerate替代range(len())写法可减少38%的索引错误概率。本文通过12个生产...

Python入门到脱坑经典案例—列表去重

列表去重是Python编程中常见的操作,下面我将介绍多种实现列表去重的方法,从基础到进阶,帮助初学者全面掌握这一技能。方法一:使用集合(set)去重(最简单)pythondefremove_dupl...

Python枚举类工程实践:常量管理的标准化解决方案

本文通过7个生产案例,系统解析枚举类在工程实践中的应用,覆盖状态管理、配置选项、错误代码等场景,适用于Web服务开发、自动化测试及系统集成领域。一、基础概念与语法演进1.1传统常量与枚举类对比#传...

让Python枚举更强大!教你玩转Enum扩展

为什么你需要关注Enum?在日常开发中,你是否经常遇到这样的代码?ifstatus==1:print("开始处理")elifstatus==2:pri...

Python枚举(Enum)技巧,你值得了解

枚举(Enum)提供了更清晰、结构化的方式来定义常量。通过为枚举添加行为、自动分配值和存储额外数据,可以提升代码的可读性、可维护性,并与数据库结合使用时,使用字符串代替数字能简化调试和查询。Pytho...

78行Python代码帮你复现微信撤回消息!

来源:悟空智能科技本文约700字,建议阅读5分钟。本文基于python的微信开源库itchat,教你如何收集私聊撤回的信息。[导读]Python曾经对我说:"时日不多,赶紧用Python"。于是看...

登录人人都是产品经理即可获得以下权益

文章介绍如何利用Cursor自动开发Playwright网页自动化脚本,实现从选题、写文、生图的全流程自动化,并将其打包成API供工作流调用,提高工作效率。虽然我前面文章介绍了很多AI工作流,但它们...

Python常用小知识-第二弹(python常用方法总结)

一、Python中使用JsonPath提取字典中的值JsonPath是解析Json字符串用的,如果有一个多层嵌套的复杂字典,想要根据key和下标来批量提取value,这是比较困难的,使用jsonpat...

取消回复欢迎 发表评论: