opencv人脸识别
opencv人脸识别器:
-
EigenFaces(本征)人脸识别器识别器- cv2.face.createEigenFaceRecognizer()–只关注面部的独特特征
- 它从该新图像中提取主要成分,并将该成分与其在训练过程中存储的成分列表进行比较,找到最匹配的成分,并返回与该最匹配成分关联的人员标签。
-
FisherFaces人脸识别器识别器- cv2.face.createFisherFaceRecognizer()–前一种的改进
- Fisherfaces算法不是提取代表所有人的所有面孔的有用特征,而是提取将一个人与其他人区分开的有用特征。
- 即使在Fisherfaces算法中,如果多个人的图像由于外部光源(如光)而发生急剧变化,它们也将主导其他特征并影响识别精度。
-
本地二进制模式直方图(LBPH)人脸识别器- cv2.face.createLBPHFaceRecognizer()–克服光照对前两种的影响
- LBPH算法尝试找到图像的局部结构,并通过将每个像素与其相邻像素进行比较来做到这一点。
- 取一个3x3的窗口并将其移动一个图像,每次移动(图像的每个局部),将中心的像素与其相邻像素进行比较。强度值小于或等于中心像素的邻居用1表示,其他用0表示。然后在3x3窗口下按顺时针顺序读取这些0/1值,您将得到一个像11100011这样的二进制模式,该模式是局部的到图像的某些区域。您在整个图像上执行此操作,并且将具有本地二进制模式的列表。
- 当您将新图像提供给识别器进行识别时,它将为该新图像生成一个直方图,将该直方图与已有的直方图进行比较,找到最匹配的直方图,并返回与该最佳图像相关联的人员标签匹配直方图。
使用opencv进行人脸识别
步骤:
- 准备训练数据:我们将读取每个人/对象的训练图像及其标签,从每个图像中检测面部。
- 训练人脸识别器:向OpenCV的LBPH人脸识别器提供我们在步骤1中准备的数据,以对其进行训练。
- 测试
import cv2
import os
import numpy as np
import matplotlib.pyplot as plt
%matplotlibinline
训练数据文件夹目录
training-data
|-------------- s1
| |-- 1.jpg
| |-- ...
| |-- 12.jpg
|-------------- s2
| |-- 1.jpg
| |-- ...
| |-- 12.jpg
OpenCV人脸识别器接受标签为整数,因此我们需要定义整数标签和人员实际姓名之间的映射,因此下面我定义人员整数标签及其相应名称的映射。
#训练的数据没有标签0,所以为空
subjects = ["", "Tom Cruise", "Shahrukh Khan"]
#function to detect face using OpenCV
#截取出人脸
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)
#load OpenCV face detector, I am using LBP which is fast
#there is also a more accurate but slow Haar classifier
#加载LBP人脸检测器
face_cascade = cv2.CascadeClassifier('opencv-files/lbpcascade_frontalface.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
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]
#此函数将读取所有人的训练图像,从每个图像中检测面部
#并返回两张大小完全相同的列表,一张列表
#张面孔,以及每张面孔的另一张标签列表
def prepare_training_data(data_folder_path):
#------STEP-1--------
#get the directories (one directory for each subject) in data folder
dirs = os.listdir(data_folder_path)
#list to hold all subject faces
faces = []
#list to hold labels for all subjects
labels = []
#let's go through each directory and read images within it
for dir_name in dirs:
#our subject directories start with letter 's' so
#ignore any non-relevant directories if any
if not dir_name.startswith("s"):
continue;
#------STEP-2--------
#extract label number of subject from dir_name
#format of dir name = slabel
#, so removing letter 's' from dir_name will give us label
label = int(dir_name.replace("s", ""))
#build path of directory containin images for current subject subject
#sample subject_dir_path = "training-data/s1"
subject_dir_path = data_folder_path + "/" + dir_name
#get the images names that are inside the given subject directory
subject_images_names = os.listdir(subject_dir_path)
#------STEP-3--------
#go through each image name, read image,
#detect face and add face to list of faces
for image_name in subject_images_names:
#ignore system files like .DS_Store
if image_name.startswith("."):
continue;
#build image path
#sample image path = training-data/s1/1.pgm
image_path = subject_dir_path + "/" + image_name
#read image
image = cv2.imread(image_path)
#display an image window to show the image
cv2.imshow("Training on image...", image)
cv2.waitKey(100)
#detect face
face, rect = detect_face(image)
#------STEP-4--------
#for the purpose of this tutorial
#we will ignore faces that are not detected
if face is not None:
#add face to list of faces
faces.append(face)
#add label for this 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 and labels
print("Total faces: ", len(faces))
print("Total labels: ", len(labels))
开始训练(使用LBPH)
face_recognizer = cv2.face.createLBPHFaceRecognizer()
face_recognizer.train(faces, np.array(labels))
预测
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.
#cv2.putText(img, text, startPoint, font, fontSize, rgbColor, lineWidth)
def draw_text(img, text, x, y):
cv2.putText(img, text, (x, y), cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 0), 2)
def predict(test_img):
#make a copy of the image as we don't want to chang original image
img = test_img.copy()
#detect face from the image
face, rect = detect_face(img)
#predict the image using our face recognizer
label= face_recognizer.predict(face)
#get name of respective label returned by face recognizer
label_text = subjects[label]
#draw a rectangle around face detected
draw_rectangle(img, rect)
#draw name of predicted person
draw_text(img, label_text, rect[0], rect[1]-5)
return img
print("Predicting images...")
#load test images
test_img1 = cv2.imread("test-data/test1.jpg")
test_img2 = cv2.imread("test-data/test2.jpg")
#perform a prediction
predicted_img1 = predict(test_img1)
predicted_img2 = predict(test_img2)
print("Prediction complete")
#create a figure of 2 plots (one for each test image)
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5))
#display test image1 result
ax1.imshow(cv2.cvtColor(predicted_img1, cv2.COLOR_BGR2RGB))
#display test image2 result
ax2.imshow(cv2.cvtColor(predicted_img2, cv2.COLOR_BGR2RGB))
#display both images
cv2.imshow("Tom cruise test", predicted_img1)
cv2.imshow("Shahrukh Khan test", predicted_img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)
cv2.destroyAllWindows()
人脸识别是一个有趣的想法,OpenCV使我们对其进行编码变得极其简单和容易。一个完整的人脸识别应用程序只需要几行代码,我们只需更改一行代码就可以在所有三个人脸识别器之间进行切换。就这么简单。
尽管EigenFaces,FisherFaces和LBPH面部识别器都不错,但是还有更好的方法来进行面部识别,例如使用定向梯度直方图(HOG)和神经网络。因此,如今已经结合使用OpenCV和机器学习来实现更高级的面部识别算法。