本帖最后由 云天 于 2021-8-8 21:14 编辑  一、OpenCV人脸识别之一:数据收集和预处理 程序的功能就是打开电脑摄像头,采集自己100张人脸图片 
 import cv2
 
 def getTrainingData(window_name, camera_id, path_name, max_num): # path_name是图片存储目录,max_num是需要捕捉的图片数量
     cv2.namedWindow(window_name) # 创建窗口
     cap = cv2.VideoCapture(camera_id) # 打开摄像头
     classifier = cv2.CascadeClassifier('haarshare/haarcascade_frontalface_alt2.xml') # 加载分类器
     color = (0,255,0) # 人脸矩形框的颜色
     num = 0 # 记录存储的图片数量
 
     while cap.isOpened():
         ok, frame = cap.read()
         if not ok:
             break
 
         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 灰度化
         faceRects=classifier.detectMultiScale(gray,scaleFactor=1.2,minNeighbors=3,minSize=(32,32))
 
         if len(faceRects) > 0:
             for faceRect in faceRects:
                 x,y,w,h = faceRect
                 # 捕捉到的图片的名字,这里用到了格式化字符串的输出
                 image_name = '%s%d.jpg' % (path_name, num) # 注意这里图片名一定要加上扩展名,否则后面imwrite的时候会报错:could not find a writer for the specified extension in function cv::imwrite_ 参考:https://stackoverflow.com/questions/9868963/cvimwrite-could-not-find-a-writer-for-the-specified-extension
                 image = frame[y:y+h, x:x+w] # 将当前帧含人脸部分保存为图片,注意这里存的还是彩色图片,前面检测时灰度化是为了降低计算量;这里访问的是从y位开始到y+h-1位
                 cv2.imwrite(image_name, image)
 
                 num += 1
                 # 超过指定最大保存数量则退出循环
                 if num > max_num:
                     break
 
                 cv2.rectangle(frame, (x,y), (x+w,y+h), color, 2) # 画出矩形框
                 font = cv2.FONT_HERSHEY_SIMPLEX # 获取内置字体
                 cv2.putText(frame, ('%d'%num), (x+30, y+30), font, 1, (255,0,255), 4) # 调用函数,对人脸坐标位置,添加一个(x+30,y+30)的矩形框用于显示当前捕捉到了多少人脸图片
         if num > max_num:
             break
         cv2.imshow(window_name, frame)
         c = cv2.waitKey(10)
         if c & 0xFF == ord('q'):
             break
 
     cap.release()#释放摄像头并销毁所有窗口
     cv2.destroyAllWindows()
     print('Finished.')
 #主函数
 if __name__ =='__main__':
     print ('catching your face and writting into disk...')
     getTrainingData('getTrainData',0,'training_data/',100) # 注意这里的training_data_xx 文件夹就在程序工作目录下
 复制代码 二、模型训练 
 #import OpenCV module
 import cv2
 #import os module for reading training data directories and paths
 import os
 #import numpy to convert python lists to numpy arrays as 
 #it is needed by OpenCV face recognizers
 import numpy as np
 
 #使用OpenCV用来检测脸部的函数
 def detect_face(img):
     #将测试图像转换为灰度图像,因为opencv人脸检测器需要灰度图像
     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
     
     #加载OpenCV人脸检测器,我正在使用的是快速的LBP
     #还有一个更准确但缓慢的Haar分类器
     face_cascade = cv2.CascadeClassifier('haarshare/lbpcascade_frontalface.xml')
 
     #让我们检测多尺度(一些图像可能比其他图像更接近相机)图像
     #结果是一张脸的列表
     faces = face_cascade.detectMultiScale(gray, scaleFactor=1.2, minNeighbors=5);
     
     #如果未检测到面部,则返回原始图像
     if (len(faces) == 0):
         return None, None
     
     #假设只有一张脸,
     #提取面部区域
     (x, y, w, h) = faces[0]
     
     #只返回图像的正面部分
     return gray[y:y+w, x:x+h], faces[0]
 #该功能将读取所有人的训练图像,从每个图像检测人脸
 #并将返回两个完全相同大小的列表,一个列表 
 # 每张脸的脸部和另一列标签
 def prepare_training_data(data_folder_path):
     
     #------STEP-1--------
     #获取数据文件夹中的目录(每个主题的一个目录)
     dirs = os.listdir(data_folder_path)
     
     #列表来保存所有主题的面孔
     faces = []
     #列表以保存所有主题的标签
     labels = []
     
     #让我们浏览每个目录并阅读其中的图像
     for dir_name in dirs:
         
         #我们的主题目录以字母's'开头
         #如果有的话,忽略任何不相关的目录
         if not dir_name.startswith("s"):
             continue;
             
         #------STEP-2--------
         #从dir_name中提取主题的标签号
         #目录名称格式= slabel
         #,所以从dir_name中删除字母''会给我们标签
         label = int(dir_name.replace("s", ""))
         
         #建立包含当前主题主题图像的目录路径
         #sample subject_dir_path = "training-data/s1"
         subject_dir_path = data_folder_path + "/" + dir_name
         
         #获取给定主题目录内的图像名称
         subject_images_names = os.listdir(subject_dir_path)
         
         #------STEP-3--------
         #浏览每个图片的名称,阅读图片,
         #检测脸部并将脸部添加到脸部列表
         for image_name in subject_images_names:
             
             #忽略.DS_Store之类的系统文件
             if image_name.startswith("."):
                 continue;
             
             #建立图像路径
             #sample image path = training-data/s1/1.pgm
             image_path = subject_dir_path + "/" + image_name
 
             #阅读图像
             image = cv2.imread(image_path)
             
             #显示图像窗口以显示图像
             cv2.imshow("Training on image...", image)
             cv2.waitKey(100)
             
             #侦测脸部
             face, rect = detect_face(image)
             
             #------STEP-4--------
             #为了本教程的目的
             #我们将忽略未检测到的脸部
             if face is not None:
                 #将脸添加到脸部列表
                 faces.append(face)
                 #为这张脸添加标签
                 labels.append(label)
             
     cv2.destroyAllWindows()
     cv2.waitKey(1)
     cv2.destroyAllWindows()
     
     return faces, labels
     #让我们先准备好我们的训练数据
 #数据将在两个相同大小的列表中
 #一个列表将包含所有的面孔
 #数据将在两个相同大小的列表中
 print("Preparing data...")
 faces, labels = prepare_training_data("training_data")
 print("Data prepared")
 
 #打印总面和标签
 print("Total faces: ", len(faces))
 print("Total labels: ", len(labels))
 print("Preparing train....")
 face_recognizer = cv2.face.LBPHFaceRecognizer_create()
 face_recognizer.train(faces, np.array(labels))
 face_recognizer.write('trainer.yml')
 print("faces trained. Exiting Program")
 
 复制代码 人脸模型。 【识别人脸】 简单说下流程: 
打开摄像头。 加载人脸检测器,加载人脸模型。 人脸检测 把检测到的人脸与人脸模型里面的对比,找出这是谁的脸。 如果人脸是自己的,显示自己的名字。 
 import cv2
 import os
 import time
 recognizer = cv2.face.LBPHFaceRecognizer_create()
 recognizer.read('trainer.yml')
 cascadePath = "haarshare/lbpcascade_frontalface.xml"
 faceCascade = cv2.CascadeClassifier(cascadePath)
 font = cv2.FONT_HERSHEY_SIMPLEX
 
 idnum = 0
 
 names = ['', 'sl','sxs','taobi']
 
 cam = cv2.VideoCapture(0)
 minW = 0.1*cam.get(3)
 minH = 0.1*cam.get(4)
 
 while True:
     ret, img = cam.read()
     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 
     faces = faceCascade.detectMultiScale(
         gray,
         scaleFactor=1.2,
         minNeighbors=5,
         minSize=(int(minW), int(minH))
     )
 
     for (x, y, w, h) in faces:
         cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
         idnum, confidence = recognizer.predict(gray[y:y+h, x:x+w])
 
         if confidence < 100:
             idnum = names[idnum]
             confidence = "{0}%".format(round(100 - confidence))
         else:
             idnum = "unknown"
             confidence = "{0}%".format(round(100 - confidence))
 
         cv2.putText(img, str(idnum), (x+5, y-5), font, 1, (0, 0, 255), 1)
         cv2.putText(img, str(confidence), (x+5, y+h-5), font, 1, (0, 0, 0), 1)
 
     cv2.imshow('camera', img)
     k = cv2.waitKey(10)
     if k == 27:
         break
 
 cam.release()
 cv2.destroyAllWindows()
 
 # def draw_rectangle(img, rect):
 #     (x, y, w, h) = rect
 #     cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
     
 # #function to draw text on give image starting from
 # #passed (x, y) coordinates. 
 # def draw_text(img, text, x, y):
 #     cv2.putText(img, text, (x, y), cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 0), 2)
 
 # def detect_face(img):
 #     #convert the test image to gray image as opencv face detector expects gray images
 #     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 #     cascadePath = 'opencv-files/lbpcascade_frontalface.xml'
 #     face_cascade = cv2.CascadeClassifier(cascadePath)
 #     #load OpenCV face detector, I am using LBP which is fast
 #     #there is also a more accurate but slow Haar classifier
 #     #face_cascade = cv2.CascadeClassifier('opencv-files/haarcascade_frontalface_alt.xml')
 
 #     #let's detect multiscale (some images may be closer to camera than others) images
 #     #result is a list of faces
 #     faces = face_cascade.detectMultiScale(gray, scaleFactor=1.2, minNeighbors=5);
 #     #if no faces are detected then return original img
 #     print(len(faces))
 #     if (len(faces) == 0):
 #         return None, None
     
 #     #under the assumption that there will be only one face,
 #     #extract the face area
 #     (x, y, w, h) = faces[0]
     
 #     #return only the face part of the image
 #     return gray[y:y+w, x:x+h], faces[0]
 
 
 # face_recognizer = cv2.face.LBPHFaceRecognizer_create()
 # face_recognizer.read('trainer.yml')
 # names = ['', 'Bob','xxx','Taotaotao']
 # print("Predicting images...")
 
 # #load test images
 # test_img = cv2.imread("1.jpg")
 # #perform a prediction
 # img = test_img.copy()
 # start=time.clock()
 # face, rect = detect_face(img)
 # label, confidence = face_recognizer.predict(face)
 # label_text = names[label]
 # end=time.clock()
 # draw_rectangle(img, rect)
 # draw_text(img, label_text, rect[0], rect[1]-5)
 
 # print("Prediction complete time %s"%(end-start))
 
 # #display both images
 # cv2.imshow("0000", cv2.resize(img, (400, 500)))
 # cv2.waitKey(3600)
 # cv2.destroyAllWindows()
 
 复制代码