pycharm+opencv实现简单人脸识别

一.配置环境

  1. 官网下载python对应版本,配置好环境变量【下载后选择直接添加到路径即可】
  2. jetbrain官网下载pycharm(社区版就行),可在设置里添加汉语包或者其他插件
  3. 下载opencv,如果使用cmd命令的pip下载不成功,就去官网下载python对应版本的opencv。并去项目设置里安装好相应的解释器和软件包

pycharm+opencv实现简单人脸识别_第1张图片

pycharm+opencv实现简单人脸识别_第2张图片

二.一些铺垫

实现一个简单功能:找到图片中的人脸:

#下载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_BGR2GRAYopencv3以上中的转换灰度格式,结束后把灰度矩阵存入gray_img

        gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)


        cv.CascadeClassifier()是调用分类器,里面的地址是opencv安装文件中的人脸分类器路径,该分类是基于haarlbp的图形识别,调用该分类器并命名为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()即是检测函数,需要另外定义。GUIimshow()不能单独使用,需要用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 数组中【要是用numpyconvert('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文件importlen(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()

你可能感兴趣的:(opencv,pycharm,python)