赞
踩
课程来源:一天搞定人脸识别项目!学不会up直接下跪!(python+opencv)_哔哩哔哩_bilibili
环境配置详见:
在conda虚拟环境中安装OpenCv并在pycharm中使用_conda虚拟环境安装opencv_好喜欢吃红柚子的博客-CSDN博客
目录
waitKey()–是在一个给定的时间内(单位ms)等待用户按键触发;
waitKey() 函数的功能是不断刷新图像 , 频率时间为delay , 单位为ms
- 返回值为当前键盘按键值
- 如果用户没有按下键,则继续等待 (循环)
- 常见 : 设置 waitKey(0) , 则表示程序会无限制的等待用户的按键事件;一般在 imgshow 的时候 , 如果设置 waitKey(0) , 代表按任意键继续
waitkey控制着imshow的持续时间,当imshow之后不跟waitkey时,相当于没有给imshow提供时间展示图像,所以只有一个空窗口一闪而过。添加了waitkey后,哪怕仅仅是cv2.waitkey(1),我们也能截取到一帧的图像。所以cv2.imshow后边是必须要跟cv2.waitkey的。
cv2.waitKey的入门级理解_山上有强强的博客-CSDN博客_cv2.waitkey
python cv2.waitKey()函数_漫天丶飞雪的博客-CSDN博客_cv2.waitkey
- #导入cv模块
- import cv2 as cv
- #读取图片
- img = cv.imread('1.png')
- #显示图片
- cv.imshow('showFace',img)
- #等待delay
- cv.waitKey(0)
- #释放内存
- cv.destroyAllWindows()

图像处理时为什么灰度化_图像灰度化处理的目的_whaosoft143的博客-CSDN博客
为什么做图片识别要将彩色图像灰度化呢?
图像灰度化的目的是为了简化矩阵,提高运算速度。
彩色图像中的每个像素颜色由R、G、B三个分量来决定,而每个分量的取值范围都在0-255之间,这样对计算机来说,彩色图像的一个像素点就会有256*256*256=16777216种颜色的变化范围!
而灰度图像是R、G、B分量相同的一种特殊彩色图像,对计算机来说,一个像素点的变化范围只有0-255这256种。
彩色图片的信息含量过大,而进行图片识别时,其实只需要使用灰度图像里的信息就足够了,所以图像灰度化的目的就是为了提高运算速度。
当然,有时图片进行了灰度处理后还是很大,也有可能会采用二值化图像(即像素值只能为0或1)。
cvtColor()
imwrite()
- #导入模块
- import cv2 as cv
- #读取图片
- img = cv.imread("face1.png")
- #灰度转换
- gray_img = cv.cvtColor(img,cv.COLOR_BGRA2GRAY)
- #显示灰度
- cv.imshow("greyImg",gray_img)
- #保存灰度图片
- cv.imwrite('gray_face1.png',gray_img)
- #等待
- cv.waitKey(0)
- #释放内存
- cv.destroyAllWindows()

在关闭显示的灰度图片后,会将该图片进行保存

resize()
- import cv2 as cv
-
- #读取图片
- img = cv.imread("face1.png")
- #修改尺寸
- img_resized = cv.resize(img,(200,200))
- #显示原图
- cv.imshow("face01",img)
- #显示修改尺寸后的图
- cv.imshow("face01_resized",img_resized)
- #打印原图和修改图的尺寸
- print("原图大小:",img.shape,"\n修改后大小:",img_resized.shape)
- #保存修改大小后的图片
- cv.imwrite("resize_face1.png",img_resized)
- #等待
- cv.waitKey(0)
- #释放内存
- cv.destroyAllWindows()



3为彩色图片的通道数。

ord('m'):返回m的ascii码
- import cv2 as cv
-
- #读取图片
- img = cv.imread("face1.png")
- #修改尺寸
- img_resized = cv.resize(img,(200,200))
- #显示原图
- cv.imshow("face01",img)
- #显示修改尺寸后的图
- cv.imshow("face01_resized",img_resized)
- #打印原图和修改图的尺寸
- print("原图大小:",img.shape,"\n修改后大小:",img_resized.shape)
- #按下m键时退出程序
- while True:
- if ord('m') == cv.waitKey(0):
- break
- #释放内存
- cv.destroyAllWindows()

cv2.rectangle(img, pt1, pt2, color, thickness=None, lineType=None, shift=None)
参数介绍:
python版opencv函数学习笔记-cv.rectangle()全参数理解_风一样的夏天001的博客-CSDN博客
作用:根据给定的左上顶点和右下顶点画矩形
参数说明:
cv2.circle(img, center, radius, color, thickness=None, lineType=None, shift=None):
作用:根据给定的圆心和半径等画圆
参数说明:
- import cv2 as cv
- x,y,w,h = 100,100,100,100
- #读取图片
- img = cv.imread("face1.png")
- #绘制矩形
- cv.rectangle(img,pt1=(x,y),pt2=(x+w,y+h),color=(0,0,255),thickness=1)
- #绘制圆形
- cv.circle(img,center=(x,y),radius=100,color=(255,0,0),thickness=2)
- #显示图片
- cv.imshow("draw_face1",img)
-
- while True:
- if ord('m')==cv.waitKey(0):
- break
- cv.destroyAllWindows()

在下图的路径中,我们可以看到需要xml文件,这些都是OpenCV中自带的分类器,根据文件名我们可以看到有识别眼睛的,身体的,脸的,等等。
使用cv.CascadeClassifier(参数:分类器所在路径)方法定义一个分类器对象。

我的分类器所在位置:
- OpenCV分类器路径:G:\conda\envs\testOpencv\Lib\site-packages\cv2\data
- 本次使用的分类器文件名:haarcascade_frontalface_alt2.xml
- 在代码中输入的完整路径(需要把右下划线改为左下划线): G:/conda/envs/testOpencv/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml
opencv人脸检测--detectMultiScale函数_walker lee的博客-CSDN博客_detectmultiscale
detectMultiScale
(self,
image: Any,
scaleFactor: Any = None,
minNeighbors: Any = None,
flags: Any = None,
minSize: Any = None,
maxSize: Any = None)
作用:
它可以检测出图片中所有的人脸,并将人脸用vector保存各个人脸的坐标、大小,用矩形Rect类表示,函数由分类器对象调用。
参数介绍:
- import cv2 as cv
-
- def face_detect_methed():
- # 图片灰度化
- grey_img = cv.cvtColor(img,cv.COLOR_BGRA2GRAY)
- # 定义分类器,使用OpenCV自带的分类器
- face_detector = cv.CascadeClassifier('G:/conda/envs/testOpencv/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml')
- # 使用分类器
- face = face_detector.detectMultiScale(grey_img)
- # 在图片中对人脸画矩阵
- for x,y,w,h in face:
- cv.rectangle(img,(x,y),(x+w,y+h),color=(0,0,255),thickness=2)
- cv.imshow('result',img)
-
- #读取图像
- img = cv.imread("face1.png")
- #调用检测函数
- face_detect_methed()
-
-
- while True:
- if ord('m') == cv.waitKey(0):
- break
-
- cv.destroyAllWindows()

此时为没有设定参数,可以看到图片识别人脸出现了失误,把背景中的海浪也识别为了人脸。

在调整了参数后可以看到,人脸识别正确,识别出了一个人脸

此次可以识别多个人脸,与识别一个人脸的代码基本相同,这次换了一个分类器,即OpenCV自带的默认人脸识别分类器,调整了一下detectMultiScale的参数,识别结果较为准确,但是有一个人脸未识别出来。
- import cv2 as cv
-
- def face_detect_methed():
- # 图片灰度化
- grey_img = cv.cvtColor(img,cv.COLOR_BGRA2GRAY)
- # 定义分类器,使用OpenCV自带的分类器
- face_detector = cv.CascadeClassifier('G:/conda/envs/testOpencv/Lib/site-packages/cv2/data/haarcascade_frontalface_default.xml')
- # 使用分类器
- face = face_detector.detectMultiScale(grey_img,1.1,5,0,(10,10),(200,200))
- # 在图片中对人脸画矩阵
- for x,y,w,h in face:
- cv.rectangle(img,(x,y),(x+w,y+h),color=(0,0,255),thickness=2)
- cv.imshow('result',img)
-
- #读取图像
- img = cv.imread("faceMorePeople.png")
- #调用检测函数
- face_detect_methed()
-
- while True:
- if ord('m') == cv.waitKey(0):
- break
-
- cv.destroyAllWindows()


可以看到识别的不算准确,c位的人脸没有被识别出来,我挑了很多次参数也换了分类器还是不行,就这样吧那~

换了一张有两个人脸的照片,可以检测出来。

cap = cv2.VideoCapture(filepath)
cap为读取摄像头或视频的对象。
flag, frame = cap.read()
在这里我们需要使用一个循环判断是否捕获到图像:
- while True:
- flag,frame = cap.read()
- if not flag:
- break
- face_detect_method(frame)
- if ord('c')==cv.waitKey(1):
- break
cap.release()
使用结束后释放摄像头资源。
需要设置WaitKey方法的参数为1,如果为0的话则只能捕获到视频的第一帧,不能播放视频。

可以看到
- import cv2 as cv
-
- # 检测方法定义
- def face_detect_method(img):
- grey_img = cv.cvtColor(img,cv.COLOR_BGRA2GRAY)
- face_detector = cv.CascadeClassifier("G:/conda/envs/testOpencv/Lib/site-packages/cv2/data/haarcascade_frontalface_default.xml")
- face = face_detector.detectMultiScale(grey_img,1.02,4)
- for x,y,w,h in face:
- cv.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
- cv.imshow("result",img)
-
- #读取摄像头
- cap = cv.VideoCapture(0)
- #读取视频
- #cap = cv.VideoCapture('G:/1.mp4')
-
- # 循环判断
- while True:
- flag,frame = cap.read()
- if not flag:
- break
- face_detect_method(frame)
- if ord('c')==cv.waitKey(1):
- break
-
- cv.destroyAllWindows()
- cap.release()

可以看到打开摄像头后成功识别到了我的脸,两个人的也可以识别。


使用如下语句读取存储的视频:
cap = cv.VideoCapture('G:/1.mp4')
- import cv2 as cv
-
- # 检测方法定义
- def face_detect_method(img):
- grey_img = cv.cvtColor(img,cv.COLOR_BGRA2GRAY)
- face_detector = cv.CascadeClassifier("G:/conda/envs/testOpencv/Lib/site-packages/cv2/data/haarcascade_frontalface_default.xml")
- face = face_detector.detectMultiScale(grey_img,1.02,4)
- for x,y,w,h in face:
- cv.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
- cv.imshow("result",img)
-
- #读取摄像头
- #cap = cv.VideoCapture(0)
- #读取视频
- cap = cv.VideoCapture('G:/1.mp4')
-
- # 循环判断
- while True:
- flag,frame = cap.read()
- if not flag:
- break
- face_detect_method(frame)
- if ord('c')==cv.waitKey(1):
- break
-
- cv.destroyAllWindows()
- cap.release()

试了一段去青岛旅游的时候拍的视频,效果还是可以的,大部分的人脸都能识别出来。

cap.isOpened()
判断视频对象是否成功读取,成功读取视频对象返回True。
cv2.waitKey(1000) & 0xFF == ord(‘q’) 是什么意思
- cv2.waitKey(1000):在1000ms内根据键盘输入返回一个值
- 0xFF :一个十六进制数
- ord('q') :返回q的ascii码
0xFF是一个十六进制数,转换为二进制是11111111。waitKey返回值的范围为(0-255),刚好也是8个二进制位。那么我们将 cv2.waitKey(1) & 0xFF计算一下(不知怎么计算的可以百度位与运算)发现结果仍然是waitKey的返回值,那为何要多次一举呢?直接 cv2.waitKey(1) == ord('q')不就好了吗。
实际上在linux上使用waitkey有时会出现waitkey返回值超过了(0-255)的范围的现象。通过cv2.waitKey(1) & 0xFF运算,当waitkey返回值正常时 cv2.waitKey(1) = cv2.waitKey(1000) & 0xFF,当返回值不正常时,cv2.waitKey(1000) & 0xFF的范围仍不超过(0-255),就避免了一些奇奇怪怪的BUG。
- import cv2 as cv
- #创建摄像头对象
- cap = cv.VideoCapture(0)
- #记录保存图片的数目
- num = 1
-
- # 当摄像头开启时
- while(cap.isOpened()):
- ret,frame = cap.read()
- cv.imshow("show",frame)
- # 获取按键
- k = cv.waitKey(1)&0xFF
- #按下s保存图像
- if k ==ord('s'):
- cv.imwrite("H:/face_detect_save/"+"People"+str(num)+".face"+".jpg",frame)
- print("sucessfully saved"+str(num)+".jpg")
- print("---------------")
- #计数加一
- num+=1
- #按下空格退出
- elif k==ord(' '):
- break
-
- cap.release()
- cv.destroyAllWindows()

程序开始运行时,摄像头会自动打开,按下s键后可以保存图片到对应的路径中。
我保存了两张图片,可以看到对应的文件夹中已经进行了显示。

用图片训练一个LBPH的识别器,这里使用15张


9.2.1 采集图片文件夹中的所有文件
os.listdir可以获取path中的所有图像文件名,然后使用os.path.join方法把文件夹路径和图片名进行拼接,存储在imagePaths列表中,此时列表中存储的就是图片的完整路径,方便下一步open该图片。
解决方法:使用pip install命令安装opencv-库

解决:需要提前手动在项目目录下创建好trainer文件夹

- import os
- import cv2 as cv
- from PIL import Image
- import numpy as np
-
- def getImageAndLabels(path):
- #存储人脸数据
- faceSamples = []
- #存储姓名数据
- ids=[]
- #储存图片信息
- imagePaths = [os.path.join(path,f) for f in os.listdir(path)]
- #人脸检测分类器
- face_detecter = cv.CascadeClassifier('G:/conda/envs/testOpencv/Lib/site-packages/cv2/data/haarcascade_frontalface_default.xml')
- #遍历列表中的图片
- for imagePath in imagePaths:
- #打开图片,灰度化
- PIL_img = Image.open(imagePath).convert('L')
- #把图像转换为数组,
- img_numpy = np.array(PIL_img,'uint8')
- #获取图片人脸特征
- faces = face_detecter.detectMultiScale(img_numpy)
- #获取每张图片的id和姓名
- id = int(os.path.split(imagePath)[1].split('.')[0])
- #预防无面容照片
- for x,y,w,h in faces:
- ids.append(id)
- faceSamples.append(img_numpy[y:y+h,x:x+w])
-
- #打印脸部特征和id
- print('id:',id)
- print('fs:',faceSamples)
- return faceSamples,ids
-
- if __name__ == '__main__':
- #图片路径
- path = './data/jm/'
- #获取图像数组和id标签数组
- faces,ids = getImageAndLabels(path)
- #加载识别器
- recognizer = cv.face.LBPHFaceRecognizer_create()
- #训练
- recognizer.train(faces,np.array(ids))
- #保存文件
- recognizer.write('trainer/trainer.yml')

trainer文件夹中产生了对应的trainer.yml文件。

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。