赞
踩
说实话,这个是真的太费精力了,我们采用python和opencv来实现,这个python的版本, opencv的版本下载,在pycharm编译器中真的找了一大堆看着头大。
这里只介绍我觉得比较方便并且操作起来容易好理解的。
首先,python的下载,我们需要下载一个python的版本,而这个版本最好是3.6,因为大部分教程中的版本都是3.6。在我尝试3.11,3.9各种报错之后,我乖乖的选择了3.6.7。
找到官网下载安装到一个你知道的路径即可,建议将下载连接放到迅雷等下载软件中下载可以秒下载。
其次,pycharm准备好即可,没有特别的要求。在建立新项目的时候在选择python解释器的时候,选择你之前准备好的python版本,在选择项目路径的时候提前建好文件夹。
最后,是安装包的通用流程。可以用pip,可以直接把包给复制到你的vene下的site-package中。但是最保险的是直接用pycharm去安装。在pycharm下面有一行里有一个Python Package点击之后,可以看到你安装的包,这个时候点齿轮设置按钮,这个是可以来加下载的源,我们可以添加国内的镜像网站,来保证下载的更快。在插件库URL中加上https://pypi.tuna.tsinghua.edu.cn/simple/ 。清华的源,也可以加别的。之后应用 确定。
然后关掉,进入设置,项目,Python解释器。点进去之后看到软件包,点击加号搜索open-python点击下载即可,这里要保证你的版本是和python版本匹配。3.6.7是和opencv4.5.5.62。如果前面都正确,下载速度非常快,几秒。就把新的opencv的包加入到了环境里。
还需要安装opencv的源码来最终调用后面提到的训练好的分类器。opencv.org 官网下载,得到地址后使用迅雷。安装到自定的一个路径下。
基础版本对指定的照片进行识别。
opencv+python
判断的几个流程是:导入分类器文件,读入图片,转为灰阶图,调用detectMultiScale,绘制矩形框标记人脸,输出图像。
级联分类器:CascadeClassifier就是opencv下objdetect模块中用来做目标检测的级联分类器的一个类,它可以帮助我们检测例如车牌、眼睛、人脸等物体。
而实现的这个模型就在最后安装的opencv源码中,sources/data/haarcascades.里面 haarcascade_frontalface_alt2.xml 和 haarcascade_frontalface_default.xml 都可以使用。
import cv2 as cv # 读入图像 img = cv.imread('3.jpg') # 把图像转化成灰度 gary = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 导入分类器文件 face_detect = cv.CascadeClassifier('D:/soft/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml') # 调用detectMultiScale函数检测 face = face_detect.detectMultiScale(gary) num = 0 # 绘制矩形框标记人脸 for x, y, w, h in face: cv.rectangle(img, (x, y), (x+w, y+h), color=(0, 0, 255), thickness=1) num = num+1 # 输出图像 cv.imshow('result', img) print("照片里有", num, "个人") cv.waitKey(0)
VideoCapture
我理解是从视频中抓取图片,cv.VideoCapture(0)是从本地的摄像头抓取,括号内部’1.mp4’,就是从视频中抓取。
cap.read():是从抓取到的图片中得到数据,如果有图像返会第一个值为true,否则为false。第二个是图片格式。
我们不断检测是否从图像中抓取到了图像,如果有图像就检测是否有人脸,循环,并且每次抓取等待时间为1/24s,就是24帧,可以达到动起来的效果。直到按下q退出。
cap = cv.VideoCapture(0)
# cap = cv.VideoCapture('1.mp4')
while True :
flag,frame = cap.read()
if not flag :
break
face_detect_demo(frame)
if ord('q') == cv.waitKey(1000//24):
break
cv.destroyAllWindows()
cap.release()
还是使用VideoCapture采集视频中的图像
read()得到信息,展示出图像,并且当按下s时候保存图片
保存图片:使用的是cv.imwrite(“路径”+str(num)+“.name”+“.jpg”,frame)
waitKey:括号内,1表示间隔时间是1ms,如果是0则是一直暂停。
总体流程是:先获取路径下所有照片的脸部信息和id。然后加载识别器。把刚刚的信息用识别器训练,然后把识别器储存在指定路径下。
# 获得路径下的信息
faces, ids = getImageAndLabels(path)
# 加载识别器
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 训练
recognizer.train(faces, np.array(ids))
# 保存文件
recognizer.write('trainer/trainer.yml')
1.取出路径下所有照片的路径。
# 存储图片信息,也就是图片的路径,os.listdir(path)是把path路径下的所有文件都遍历一遍,存储到f中,然后用os.path.join拼接起来。
# 存给imagePaths,也就存下了图片的路径。
imagePaths=[os.path.join(path,f) for f in os.listdir(path)]
2.遍历所有该路径下的图片,加载为灰度图片,再将灰度图片变成矩阵,使用这个矩阵来调取面部的分类器 得到面部数据,再用每张图片前的信息来储存id,使用os.path.split来存下序号
note:os.path.split(path) 会把这个路径分为两个部分一个是前面的位置,一个是文件本身的名字。
例如:./data/jm/1.beauty.jpg 。那么os.path.split(path)[0] = /data/jm 。而os.path.split(path)[1] = 1.beauty.jpg 。
note:再使用split函数本身,xxx.split(‘以什么为分割’)[分割后排序第几]。
例子:path:1.beauty.jpg 。path.split(‘.’)[0] = 1 。表示的就是以‘.'为分割,有三个部分第0个是1.
PLUS:多一个步骤,把所有脸部信息存到faces之后,为了防止没有脸的情况,还需要遍历一遍faces,把所有的脸部信息的正方形所在区域的矩形传给另外一个储存的facesSamples,这个里面存储的就是面部的信息
def getImageAndLabels(path): #储存人脸数据 facesSamples=[] #存储姓名数据 ids=[] # 存储图片信息,也就是图片的路径,os.listdir(path)是把path路径下的所有文件都遍历一遍,存储到f中,然后用os.path.join拼接起来。 # 存给imagePaths,也就存下了图片的路径。 imagePaths=[os.path.join(path,f) for f in os.listdir(path)] # 加载分类器 face_detector = cv2.CascadeClassifier('D:/soft/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml') # 遍历列表中的图片 for imagePath in imagePaths: # 可能路径下有多张图片 # 打开图片(PIL有9种不同的模式)L是灰度图片,以灰度图片加载。 PIL_img = Image.open(imagePath).convert('L') # 将图片转化成数组,以黑白深浅 img_numpy = np.array(PIL_img, 'uint8') # 用数组以及分类器,获取图片人脸的特征 faces = face_detector.detectMultiScale(img_numpy) # 获取每张图片的id和名字,分解imagePath中的,总之就是取到这个图片的1.之前的1 id = int(os.path.split(imagePath)[1].split('.')[0]) # 预防没有面容的图片 # 将有脸的图片id都存下来了。 for x,y,w,h in faces: ids.append(id) # 如果一张图片中有多张脸,都是同一个id放入ids中 facesSamples.append(img_numpy[y:y+h, x:x+w]) # 打印脸部特征和id print('id:', id) print('fs:', facesSamples) return facesSamples, ids
首先,把图片转为灰度,并且用面部分类器,把面部数据传到face。检查face的数据,画出框和圆。
用recogizer.predict(灰度图的面部),返回的是标签编号(按照图片命名格式的第一位)和置信度。
如果置信度大于80,就说明不太一致。warningtime++,直到warning的值大于1000,会打印warning,并且在标签上输出unknow。
如果小于80,说明相似度还是很高的,按照id来找到图片命名格式中的第1个元素(也就是名字),显示到图片上。
def face_detect_demo(img): gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度 face_detector=cv2.CascadeClassifier('D:/soft/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml') face=face_detector.detectMultiScale(gray,1.1,5,cv2.CASCADE_SCALE_IMAGE,(100,100),(300,300)) # face=face_detector.detectMultiScale(gray) 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]) print('标签id:',ids) # 由于我们得到的ids是在照片上标记的,如果命名格式中断了,就会在后面names中ids-1,找不到这个names,会报错,例如我给我的照片标记为3.但是目前没有2. # 得到的ids就是3,那么找这个names的时候ids-1=2,没有2,就会报错。如果正常情况,那么ids是3 ,names从0开始计数所以是3-1=2。 print('标签id:',ids,'置信评分:', confidence) if confidence > 80: global warningtime warningtime += 1 if warningtime > 100: # warning() print("warning") warningtime = 0 cv2.putText(img, 'unknow', (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) #print('bug:',ids)
name()模块负责给names数组赋值,按照顺序存放文件下的名字。
def name():
path = './data/jm/'
#names = []
imagePaths=[os.path.join(path,f) for f in os.listdir(path)]
for imagePath in imagePaths:
name = str(os.path.split(imagePath)[1].split('.')[1])
names.append(name)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。