#下载opencv-python4.6软件包,导入cv模块
import cv2 as cv
def face_detect_demo():
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 调用cvtcolor(待修改图片名字,修改颜色)
# face_detect=cv.CascadeClassifier('D:/PCgames/GTA5/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml') #调用分类器
face_detect=cv.CascadeClassifier('D:/PCgames/GTA5/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml')
face=face_detect.detectMultiScale(gray_img)
for x,y,w,h in face:
cv.rectangle(img,(x,y),(x+w,y+h),color=(255,255,0),thickness=2) #调用rectangle(name,(左上角坐标,右下角坐标),颜色,厚度
# cv.circle(resize_img,center=(x+w,y+h),radius=100,color=(255,0,0),thickness=1)) #调用circle(name,(圆心坐标,半径),颜色,厚度)
cv.imshow('result',img) #调用imshow,显示图片
这是一个检测函数,思路是先给读取的图片进行灰度化,cv.cvtColor()是opencv中转换色彩空间的函数,img是待改变的图片像素矩阵,cv.COLOR_BGR2GRAY是opencv3以上中的转换灰度格式,结束后把灰度矩阵存入gray_img。
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.CascadeClassifier()是调用分类器,里面的地址是opencv安装文件中的人脸分类器路径,该分类是基于haar和lbp的图形识别,调用该分类器并命名为face_detect
face_detect=cv.CascadeClassifier('D:/PCgames/GTA5/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml')
接下来从整图的灰度矩阵里获取人脸部分的灰度矩阵,调用分类器中的detectMultiScale(),这个函数里有诸多参数可以调节识别的精度和次数等等,此处默认值,此函数返回的值是图片中人脸的起点坐标和长宽(x,y,w,h),存入face中
face=face_detect.detectMultiScale(gray_img)
遍历face里的(x,y,w,h), 然后调用cv.rectangle()绘制矩形
for x,y,w,h in face:
cv.rectangle(img,(x,y),(x+w,y+h),color=(255,255,0),thickness=2)
cv.imshow('result',img)
思路总结:先转换图片色彩空间,然后调用分类器中的人脸识别函数获取人脸范围坐标,然后按照图片的这个范围上绘制矩形,并imshow图片
img=cv.imread('pic4.jpg') #读取一张图片命名为img
while True: #循环
# flag,frame=cap.read() #读取视频赋值给frame,用flag判断视频是否为空
# if not flag:
# break
face_detect_demo()
if ord('Q')==cv.waitKey(0):
break
这里的思路是,先读取图片'pic4.jpg'存入img,此时如果print(img)则会在控制台输出像素矩阵,即每个点的rgb三元组构成的矩阵,注意图片路径,此处是和py项目在同一文件夹下的情况
然后进行图片检测,之所以用while true是为了给一个break条件。
img=cv.imread('pic4.jpg'),
while True:
face_detect_demo()
if ord('Q')==cv.waitKey(0):
break
只有face_detect_demo()和cv.waitKey(0)也可以
face_detect_demo()
cv.waitKey(0)
其中face_detect_demo()即是检测函数,需要另外定义。因GUI中imshow()不能单独使用,需要用cv.waitKey(0)控制图片显示时间:括号里为0表示静止当前帧,其他数字是需要等待的毫秒【此处的imshow()位于函数中的最后一步】。cv.waitKey()会返回等待期间键盘输入的字符的asc码,ord('Q')会返回Q的asc码。if两者值相等就break即按Q结束检测
思路总结:先读取图片,然后定义face_detect_demo()函数在人脸范围上添加矩形,最按Q结束检测
思路设计:与图片检测类似,先读取视频或者摄像头画面中的视频帧,将帧图片传入face_detect_demo()后绘制范围矩形,然后最按s把当前帧保存到指定文件夹并命名,按t结束程序
def face_detect_demo(img):
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 调用cvtcolor(待修改图片名字,修改颜色)
# face_detect=cv.CascadeClassifier('D:/PCgames/GTA5/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml') #调用分类器
face_detect=cv.CascadeClassifier('D:/PCgames/GTA5/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml')
face=face_detect.detectMultiScale(gray_img) #重复检测5次 每次缩放倍数为1.1
for x,y,w,h in face:
cv.rectangle(img,(x,y),(x+w,y+h),color=(0,255,0),thickness=3) #调用rectangle(name,(左上角坐标,右下角坐标),颜色,厚度
# cv.circle(resize_img,center=(x+w,y+h),radius=100,color=(255,0,0),thickness=1)) #调用circle(name,(圆心坐标,半径),颜色,厚度)
cv.imshow('result',img) #调用imshow,显示图片
这是 face_detect_demo()函数,注意此时需要给它传入参数,因为视频帧的获取要在其他函数里进行,不可以是全局变量,而图片读取可以在最外层也即是可以定义为全局变量。
cap=cv.VideoCapture(0) #调用摄像头
#cap=cv.VideoCapture('video1.mp4') #这是读取对应视频
flag=1
num=1
#判断摄像头是否为空
while(cap.isOpened()):
#读取当前帧frame,并传入函数中
ret_flag,frame=cap.read()
face_detect_demo(frame)
#按s截取视频帧
if ord('s')==cv.waitKey(2):
#把视频帧写入指定地点并命名
cv.imwrite("C:/Users/KXing/Desktop/facedetecet2/opencv/data/framepic/fpic2/"+str(num)+".name"+".jpg",frame)
print("成功保存截图"+str(num)+".jpg")
print("------------------")
num+=1
elif ord('t')==cv.waitKey(2):
break
#结束后释放内存
cap.release()
cv.destroyAllWindows()
这里是先调用摄像头截取视频帧,然后把当前帧传入face_detect_demo()函数进行人脸识别和标记,并按照指定名字写入指定文件夹。此时cv.waitKey(2)中不能为0,因为0为静止当前帧。
import hashlib
import os
import tkinter.messagebox
import urllib
import urllib.request
from datetime import datetime
import cv2 as cv # 下载opencv-python4.6软件包,导入cv模块
import numpy as np
from PIL import Image
定义一个获取图片人脸信息的函数getImageAndLabels(path),imagePaths = [os.path.join(path, listname) for listname in os.listdir(path)]是将文件中图片的完整格式保存到信息数组里。然后再里面即可遍历每一张图片,把灰度矩阵保存在img_numpy 数组中【要是用numpy的convert('L')方法打开则要import numpy】。然后把img_numpy传入人脸识别模块返回图片人脸的坐标【xywh】。最后把该坐标对应的灰度矩阵和id返回
def getImageAndLabels(path):
facesSamples = [] # 定义一个数组存放脸部样本
ids = [] # 这个数组用来存放脸部样本的id
imagePaths = [os.path.join(path, listname) for listname in
os.listdir(path)] # 这个数组用来存放图片信息,os.listdir(path)返回path中的文件名按照字母排序
# os.path.join(path, f),将多个路径组合返回,这一步是把图片名和存放图片的路径组合成图片的路径
# 调用opencv库的分类器检测人脸
face_detector = cv.CascadeClassifier(
'D:/PCgames/GTA5/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml')
# 打印数组imagePaths
print('数据信息:', imagePaths)
# 遍历列表中的图片
for imagpath in imagePaths: # 这是在图片信息数组中遍历每一张图片
# 用l法打开图片,此时每个像素点可表示为一个(0-255)的值,将得到的图片存入PIL_img
PIL_img = Image.open(imagpath).convert('L')
img_image = cv.imread(imagpath) # 如果用opencv打开则显示每个像素rgb数值组成的矩阵
gray_img = cv.cvtColor(img_image, cv.COLOR_BGR2GRAY) # 用opencv调成灰色图,此时得到矩阵和img_numpy相同
print(PIL_img)
print('这是impath', imagpath)
print('这是整图灰度矩阵opencv', gray_img)
# PIL_img = cv2.resize(PIL_img, dsize=(400, 400))
img_numpy = np.array(PIL_img, 'uint8') # np.array是一种创建数组的方法,前面是创建对象,后面是元素的类型,将PIL_img创建成为矩阵,存入img_numpy
# 其中img_numpy即使所选图像的灰度值矩阵
print('这是整图的灰度矩阵numpy和PIL', img_numpy)
# 接下来从整图的灰度矩阵里获取图片人脸特征, face_detector.detectMultiScale是opencv的一个函数
# image–待检测图片,一般为灰度图像加快检测速度;objects–被检测物体的矩形框向量组;scaleFactor–表示在前后两次相继的扫描中,搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10%
# minNeighbors–表示构成检测目标的相邻矩形的最小个数(默认为3个),flags–要么使用默认值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果设置为
# CV_HAAR_DO_CANNY_PRUNING,那么函数将会使用Canny边缘检测来排除边缘过多或过少的区域,minSize和maxSize用来限制得到的目标区域的范围。
faces = face_detector.detectMultiScale(img_numpy)
print('这是faces', faces) # 返回的faces为人脸的起点以及人脸矩形的长宽(x,y,w,h)
# 获取每张图片的id和姓名,os.path.split是分离路径和和文件名函数,
id = int(os.path.split(imagpath)[1].split('.')[
0]) # os.path.split(imagePath)[0],整个路径链表的表头,os.path.split(imagePath)[1]
# os.path.split(imagePath)[1]split('.')[1],后面是指以’‘内划分链表,0为头,1为表尾
h = []
h = os.path.split(imagpath)[0].split('a')[1]
print('this is path', imagpath)
print('this is os.path', h)
# 预防无面容照片
# 在faces中遍历(x,y,w,h),把id加入数组,把人脸灰度矩阵加入数组
for x, y, w, h in faces:
ids.append(id)
facesSamples.append(img_numpy[y:y + h, x:x + w])
# 打印脸部特征和id
print('fs:', facesSamples)
print('id:', id)
# print('fs:', facesSamples[id])
# print('fs:', facesSamples)
# print('脸部例子:',facesSamples[0])
# print('身份信息:',ids[0])
return facesSamples, ids
定义一个train()函数 ,if __name__ == '__main__':内的内容不会被其他py文件import。len(os.listdir(path))即是获取路径内文件名字的长度,若存在图片就调用getImageAndLabels()函数返回文件夹中图片的面部灰度矩阵和id。然后调用cv.face.LBPHFaceRecognizer_create(内有若干参数可选) 生成LBPH识别器实例模型recognizer,然后调用recognizer.train ( )函数训练,并将训练结果存入指定文件的yml文件里。再识别时会读取该文件数据。
def train():
#这个if可以让内部内容不被其他文件import
if __name__ == '__main__':
path = 'C:/Users/KXing/Desktop/facedetecet2/opencv/data/framepic/fpic/'
if len(os.listdir(path)) > 0:
# 调用函数,获取面部灰度矩阵和对应的id,存入faces和ids
faces, ids = getImageAndLabels(path)
# 调用cv.face.LBPHFaceRecognizer_create(),这是opencv中基于lbph算法的函数
recognizer = cv.face.LBPHFaceRecognizer_create()
print('this is rec', recognizer)
# # recognizer.train(faces,names)#np.array(ids)
# # 训练函数,传入面部矩阵数组和id数组
recognizer.train(faces, np.array(ids))
# 注意此处的faces是函数里的结果之一
# # 保存文件,写入trainer.yml,此文件用来进行面部对比
recognizer.write('C:/Users/KXing/Desktop/facedetecet2/opencv/data/trainer.yml')
开始识别:
def name():
path = 'C:/Users/KXing/Desktop/facedetecet2/opencv/data/framepic/fpic/'
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])
# print("aSDF", name)
inames.append(name)
def face_detect(img):
# recogizer = cv.face.LBPHFaceRecognizer_create()
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 转换为灰度
face_detector = cv.CascadeClassifier(
'D:/PCgames/GTA5/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml')
face = face_detector.detectMultiScale(gray, 1.1, 5, cv.CASCADE_SCALE_IMAGE, (100, 100), (300, 300))
# face=face_detector.detectMultiScale(gray)
for x, y, w, h in face:
cv.rectangle(img, (x, y), (x + w, y + h), color=(0, 0, 255), thickness=2)
cv.circle(img, center=(x + w // 2, y + h // 2), radius=w // 2, color=(0, 255, 0), thickness=1)
# 人脸识别
ids, confidence = recognizer.predict(gray[y:y + h, x:x + w])
# recognizer.predict()进行对比,返回id和confidence值,这个值用来衡量相似度
# print('标签id:',ids,'置信评分:', confidence)
if confidence > 80:
global warningtime
warningtime += 1
if warningtime > 100:
warning()
warningtime = 0
#这里是给画面矩形框添加识别结果的文本
cv.putText(img, 'unkonw', (x + 10, y - 10), cv.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1)
else:
cv.putText(img, str(inames[ids-2]) , (x + 10, y - 10), cv.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1)
cv.imshow('detectresult', img)
def train():
if __name__ == '__main__':
path = 'C:/Users/KXing/Desktop/facedetecet2/opencv/data/framepic/fpic/'
if len(os.listdir(path)) > 0:
# 调用函数,获取面部灰度矩阵和对应的id,存入faces和ids
faces, ids = getImageAndLabels(path)
# 调用cv.face.LBPHFaceRecognizer_create(),这是opencv中基于lbph算法的函数
recognizer = cv.face.LBPHFaceRecognizer_create()
print('this is rec', recognizer)
# # recognizer.train(faces,names)#np.array(ids)
# # 训练函数,传入面部矩阵数组和id数组
recognizer.train(faces, np.array(ids))
print('what is it ?', recognizer.train(faces, np.array(ids))) # 注意此处的faces是函数里的结果之一
# # 保存文件,写入trainer.yml,此文件用来进行面部对比
recognizer.write('C:/Users/KXing/Desktop/facedetecet2/opencv/data/trainer.yml')
def detectfin():
# pathyml = ('C:/Users/KXing/Desktop/facedetecet2/opencv/data/')
# if len(os.listdir(pathyml)) > 0:
flag = 1
cap = cv.VideoCapture(0)
name()
while (cap.isOpened()):
ret_flag, frame = cap.read()
face_detect(frame)
if ord(' ') == cv.waitKey(10):
# flaglo = 0
break
cv.destroyAllWindows()
cap.release()
train()
detectfin()