基于Python的人脸识别

简单介绍

本代码分成三块:

  1. 人脸录入模块:识别前得录入吧,就在这里录入
  2. 人脸识别模块:录入之后识别就完事了
  3. 公共函数模块:把1和2模块之中的共用模块拿下来放到一起

代码之外的一些轶事(anecdote)

中期检查的时候,我用的外部人脸库,答辩组说:你这没有自己的人脸库,有什么实用价值?
毕业答辩的时候,我用的自己的人脸库,答辩组说:你这没有外部的人脸库,你怎么证明你代码标准?
我:????

你是故意找茬是不是?你看不看吧?(哈哈哈)

上代码!!!

1,人脸录入

 import common_function as cf
import cv2
import os
import sys
import numpy
MAX = 10  #设置保存照片的数量

def set_save_path(save_path):#设置保存图片的路径
    return save_path
save_path = set_save_path("C:/imgs")

def save():#主函数
        #获取要保存人脸的名字
        name = get_name()
        #保存图片
        save_pic(save_path,name)
        
def save_pic(filepath,name):        #本代码实现保存1个人的MAX个脸
    num_face = 0 # 用来停止循环的标志
    cap = cv2.VideoCapture(0)#打开相机
    print("已打开相机,请切到相机界面")
    print("拍摄比较多的照片时(比如大于100张),请一定要保证面部一直在摄像头内")
    while cap.isOpened():
        if  num_face > 0:#第一个人拍完之后,就结束(一次只拍一个人)
            print("共"+(str)(MAX)+"张照片,"+"已拍摄完毕")
            cv2.destroyWindow("take pictures")
            cv2.destroyAllWindows()
            return True
        ret,pic =cap.read()
        cv2.putText(pic,"press 'Enter' to take pictures or 'Esc' to exit",
                    (25,25),
                    cv2.FONT_HERSHEY_SIMPLEX,
                    0.75,
                    (0,0,255),2)
        cv2.namedWindow("take pictures")#建立拍照窗口
        cv2.imshow("take pictures",pic)
        flag = cv2.waitKey(1)
        gray = pic #保存照片
        #(其实不需要保存为灰度图片,
        #   因为读取的时候可以以灰度图片格式读取)
        if flag == 27:#ESC
            cv2.destroyWindow("take prictures")
            cv2.destroyAllWindows()
            print("exit!")
            sys.exit(0)
        elif flag == 13:#ENTER
            num_pic=0    
            while num_pic < MAX:#截取和保存MAX个人脸照片
                ret,pic =cap.read()
                gray = pic
                face = cf.face_model_cas.detectMultiScale(gray,#检测人脸
                                           scaleFactor = 1.2,
                                           minNeighbors = 3,
                                           minSize = (128,128))                     #返回[[x,y,w,h]]
                x,y,w,h = face[0]
                image = gray[y : y + h , x : x + w ]#截取
                cv2.imwrite(filepath+"/"+name+"_"+(str)(num_pic)+".jpg",image)#进行保存
                #保存一个照片就+1
                num_pic+=1              
                #画出矩形框
                face = cf.face_model_cas.detectMultiScale(gray,#return [[x,y,w,h]]
                                           scaleFactor = 1.2,
                                           minNeighbors = 3,
                                           minSize = (128,128))
                x,y,w,h=face[0]
                cv2.rectangle(pic, (x - 10, y - 10), (x + w + 10, y + h + 10), (255,0,0), 2)               
                #显示当前捕捉到了多少人脸图片
                font = cv2.FONT_HERSHEY_SIMPLEX
                cv2.putText(pic,'num:%d' % (num_pic),(x + 30, y + 30), font, 1, (255,0,255),4)                
                cv2.imshow("take pictures",pic)
                cv2.waitKey(1)
        else :#如果输入的不是ESC或ENTER,就继续循环
            continue
        num_face+=1#结束循环
        
def get_name():#读取保存的名字
    print("请输入保存的名字(只能用英文,不然会出错)")
    name = input()
    cv2.namedWindow("take pictures")
    return name
    
if __name__ == '__main__':
    try:
        #调用save函数,保存图片
        save()
        #调用训练模块,训练图片
        cf.train(cf.set_fp(save_path),
                    cf.set_yml_path("C:/feature_victor/train.yml"))
    except(IndexError):
        print("IndexError!!!")
        print("人脸没有完整进入摄像头内,请重新运行")
    except(BaseException):
        print("出现异常")

如果有什么不懂的地方,最好先去自己查,弄懂后会收获很多。
但如果实在不懂,欢迎留言!

2,人脸识别

import cv2
import os
import numpy
import common_function as cf
import sys
import save
fp = "C:/imgs/"#图片地址
yml_path ="C:/feature_victor/train.yml"#训练文件地址

labels_name = cf.get_name(fp) 
labels_number = cf.get_number(fp,labels_name) 
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read(yml_path)

def get_num_of_name():#获取人员数量
    name_num_array = []
    len_of_name = len(labels_name)
    j = 0
    while j < len_of_name:
        count = 0
        for i in labels_number:
            if i == j:
                count +=1
            elif i > j:
                break
        j+=1
        name_num_array.append(count)
    return  name_num_array
def add_img(add_name,save_img):#新增数据库
    if add_name in labels_name:
        count=0
        for name in labels_name:
            count+=1
            if name == add_name:
                cv2.imwrite(fp+"/"+add_name+"_"+(str)(get_num_of_name()[count-1])+".jpg",save_img)
    else:
        cv2.imwrite(fp+"/"+add_name+"_0.jpg",save_img)
        
def face_recog():#主函数
        shoot_img = cf.catch_pic()
        gray = cf.bgr2gray(shoot_img)
        gray = cv2.equalizeHist(gray)
        face = cf.face_model_cas.detectMultiScale(gray,
                                                  scaleFactor = 1.2,
                                                   minNeighbors = 3,
                                                   minSize = (128,128))
        face = face[0]
        print("发现人脸")
        x,y,w,h = face
        shoot_img = shoot_img[y  : y + h ,x  : x + w ]
        gray = cv2.equalizeHist(cf.bgr2gray(shoot_img))
        label,confidence= recognizer.predict(gray)
        print("name = ",labels_name[label])
        print("confidence = ",confidence,"(越小代表越相似)")
        #optimization
        print("本次识别是否正确?y/n/q")
        while 1 :
            flag = input()
            if flag == "y":
                add_img(labels_name[label],shoot_img)
                break
            elif flag == "n":
                print("请输入本次被识别人员的名字:")
                add_name = input()
                add_img(add_name,shoot_img)
                break
            elif flag == "q":
                sys.exit(0)
            else:
                print("您输入字母的有误,请重新输入:y/n")
        cf.train(fp,yml_path)
        
if __name__ == "__main__":#用于测试
    try:
        face_recog()
    except(IndexError):
        print("人脸没有完整进入摄像头内,请重新运行")
        print("异常类型为:IndexError!")
    except(BaseException):
        print("发生了异常")
        print("异常类型为:BaseException!")

3,公共函数模块

import cv2
import numpy
import os
import sys
path="C://Users//dongdong//AppData//Roaming//Python//Python39//site-packages//cv2//data//haarcascade_frontalface_alt.xml"
face_model_cas=cv2.CascadeClassifier(path)

#拍摄一张照片并返回
def catch_pic():
    cap = cv2.VideoCapture(0)
    print("已打开相机,请切到相机界面")
    while cap.isOpened():
        ret, frame = cap.read(5)
        cv2.namedWindow("face recognition")#建立拍照窗口
        cv2.putText(frame,"press 'Enter' to take pictures or 'Esc' to exit",
                    (25,25),
                    cv2.FONT_HERSHEY_SIMPLEX,
                    0.75,
                    (0,0,255),2)
        faces = face_model_cas.detectMultiScale(frame,#return [[x,y,w,h]]
                                               scaleFactor = 1.2,
                                               minNeighbors = 3,
                                               minSize = (128,128))
        for face in faces:
            #x,y,w,h=face[0]
            x,y,w,h=face
            cv2.rectangle(frame, (x - 10, y - 10), (x + w + 10, y + h + 10), (255,0,0), 2)
            #cv2.rectangle(frame, (x , y ), (x + w , y + h), (0,255,0), 2)               
            cv2.imshow('face recognition', frame)
            flag = cv2.waitKey(1)
            if flag == 27:#按ESC键推出    
                print('系统未成功获取照片,结束识别系统')
                print("将抛出BaseException异常~")
                cap.release()
                cv2.destroyAllWindows()
                sys.exit(0)
            elif flag == 13:#按回车键拍照
                print('系统已获取照片,准备进行处理')
                cap.release()
                cv2.destroyAllWindows()          
                return frame
                
#将图片从BGR转为RGB
def bgr2rgb(img):
    return cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
#将图片从BGR转为灰度(灰度≠黑白)
def bgr2gray(img):
    return cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#--------------------------------------------------------------------------------
face_imgs = []
labels_name = []
labels_number = []  #name ->number,1 for 1

def set_fp(fp_set):#设置保存yml文件的路径
    fp = fp_set
    return  fp
    
def get_imgpaths(filepath):#获取jpg图片的文件地址,去除其他的类型文件或文件夹的地址
    imgpaths = []
    imgpaths_temp =  [os.path.join(filepath,f) for f in os.listdir(filepath)]
    for imgpath in imgpaths_temp:
        if  imgpath.endswith(".jpg"):
            imgpaths.append(imgpath)
    return imgpaths
    
def get_name(filepath):#获得名字并返回保存数组
    imgpaths = get_imgpaths(filepath)
    name_temp = []
    for imgpath in imgpaths:
        if  imgpath.endswith(".jpg"):  #如果路径有非.jpg的文件,跳过
            name = os.path.split(imgpath)[1].split(".")[0].split("_")[0]
            #print(name)
            if name not in name_temp:
                name_temp.append(name)
        else:
            continue
    return name_temp
    
def get_number(filepath,labels_name):#不同人以不同的整数保存在数组,用于训练
    imgpaths =  get_imgpaths(filepath)
    number_temp = []
    name_number = 0
    for label_name in labels_name:
        for imgpath in imgpaths:
            name = os.path.split(imgpath)[1].split(".")[0].split("_")[0]
            if name == label_name :
                number_temp.append(name_number)
        name_number+=1
    return number_temp
    
def get_img(filepath):#获取图片,存为图片数组
    img_temp = []
    imgpaths =  get_imgpaths(filepath)
    for imgpath in imgpaths:
        #新增了直方图均衡化处理
        #直方图均衡本身就已经具有亮度均衡
        img_temp.append(cv2.equalizeHist(cv2.imread(imgpath,cv2.IMREAD_GRAYSCALE)))
    return img_temp
    
def set_yml_path(yml_path):#设置训练文件的保存路径
    return yml_path
    
def train(filepath,yml_path):#主函数
    labels_name = get_name(filepath) #right
    labels_number = get_number(filepath,labels_name) #right
    face_imgs = get_img(filepath)   #right
    recognizer = cv2.face.LBPHFaceRecognizer_create()
    recognizer.train(face_imgs, numpy.array(labels_number))
    recognizer.write(yml_path)
    print("训练完成!")
    print("训练文件已经成功保存在了:"+yml_path)
    
if __name__ == "__main__":#用于测试
    train(set_fp("C:/imgs"),set_yml_path("C:/feature_victor/train.yml"))

  • 3
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值