如果说特徵脸方法是婴儿,我会说局部二值方法是会跑会跳的幼儿
局部二值方法(Local Binary Patterns),透过将
图片中的每一个像素,与其相邻的其他像素做值的大小比对与加总,得出一个图片全域相对值
图片左方是原始人脸,右方是计算LBP後的结果
从上图有几个重点可以看出:
理论上,我们是可以透过LBP计算後的特徵值,跟昨天介绍的特徵脸方法一样,来用作人脸辨识 (只要特徵一样就表示同一人);
但实际上直接使用LBP的特徵值会受特徵相对位置不一样而产生很大的误差(比如说人脸不是照片照、人脸离镜头的位置不一样等等)。
比较可行的方式,是将LBP後的特徵图片划分多个等大小的子区域,分别做直方统计图,
然後真正用来辨识的依据是这些直方统计值组合而成的局部二值直方图 (Local Binary Patterns Histogram)
讲这麽多终於进入今天的重点 -- LBPH
接下来我们会使用OpenCV内建的face_LBPHFaceRecognizer
来建立我们的人脸辨识。
face_recognition
目录,新增一个档案lbp.py
import ntpath
import sys
# resolve module import error in PyCharm
sys.path.append(ntpath.dirname(ntpath.dirname(ntpath.abspath(__file__))))
# 汇入必要套件
import argparse
import random
import time
import cv2
import numpy as np
from imutils import paths
from skimage import feature
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from dataset.load_dataset import images_to_faces
def main():
# 初始化arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input", type=str, required=True, help="the input dataset path")
args = vars(ap.parse_args())
print("[INFO] loading dataset....")
(faces, labels) = images_to_faces(args["input"])
print(f"[INFO] {len(faces)} images in dataset")
# 将名称从字串转成整数 (在做训练时时常会用到这个方法:label encoding)
le = LabelEncoder()
labels = le.fit_transform(labels)
# 将资料拆分训练用与测试用;测试资料占总资料1/4 (方便後续我们判断这个方法的准确率)
split = train_test_split(faces, labels, test_size=0.25, stratify=labels, random_state=9527)
(trainX, testX, trainY, testY) = split
print("[INFO] training...")
start = time.time()
recognizer = cv2.face_LBPHFaceRecognizer().create(radius=1, neighbors=8, grid_x=8, grid_y=8)
recognizer.train(trainX, trainY)
end = time.time()
print(f"[INFO] training took: {round(end - start, 2)} seconds")
# 辨识测试资料
print("[INFO] predicting...")
start = time.time()
predictions = []
confidence = []
# loop over the test data
for i in range(0, len(testX)):
(prediction, conf) = recognizer.predict(testX[i])
predictions.append(prediction)
confidence.append(conf)
end = time.time()
print(f"[INFO] training took: {round(end - start, 2)} seconds")
print(classification_report(testY, predictions, target_names=le.classes_))
# 随机挑选测试资料来看结果
idxs = np.random.choice(range(0, len(testY)), size=10, replace=False)
for i in idxs:
predName = le.inverse_transform([predictions[i]])[0]
actualName = le.classes_[testY[i]]
face = np.dstack([testX[i]] * 3)
face = imutils.resize(face, width=250)
cv2.putText(face, f"pred:{predName}", (5, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
cv2.putText(face, f"actual:{actualName}", (5, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
print(f"[INFO] prediction: {predName}, actual: {actualName}")
cv2.imshow("Face", face)
cv2.waitKey(0)
if __name__ == '__main__':
main()
python face_recognition/lbp.py -i dataset/caltech_faces
观看结果:radius
与neighbors
参数来提高辨识率)
precision recall f1-score support
man_1 0.83 1.00 0.91 5
man_10 1.00 1.00 1.00 6
man_11 0.86 1.00 0.92 6
man_13 1.00 1.00 1.00 5
man_14 1.00 0.86 0.92 7
man_15 0.86 1.00 0.92 6
man_2 1.00 1.00 1.00 5
man_4 1.00 1.00 1.00 6
man_5 0.86 1.00 0.92 6
man_7 1.00 1.00 1.00 5
man_9 1.00 1.00 1.00 6
woman_1 1.00 1.00 1.00 5
woman_10 1.00 1.00 1.00 6
woman_2 1.00 1.00 1.00 5
woman_5 1.00 0.67 0.80 6
woman_6 1.00 0.60 0.75 5
woman_7 1.00 1.00 1.00 6
woman_8 0.86 1.00 0.92 6
woman_9 1.00 1.00 1.00 5
accuracy 0.95 107
macro avg 0.96 0.95 0.95 107
weighted avg 0.96 0.95 0.95 107
辨识完随机选择测试图片验证# 随机选取一张照片来看LBP的结果
image_path = random.choice(list(paths.list_images(args["input"])))
image = cv2.imread(image_path)
rects = detect(image)
(x, y, w, h) = rects[0]["box"]
roi = image[y:y + h, x:x + w]
gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
lbp = feature.local_binary_pattern(gray, 8, 1, method="default")
lbp = rescale_intensity(lbp, out_range=(0, 255))
lbp = lbp.astype("uint8")
img = np.hstack([roi, np.dstack([lbp] * 3)])
cv2.imshow("img", img)
cv2.waitKey(0)
实际应用中 (比如像Day14前言提到的那种情境),人脸辨识会有各种奇怪的状况发生:
因此为了要让辨识模型更加的完善,我们需要让模型"学习"如何去辨识人脸。
这将是我们明天谈论的内容,See you!
<<: [Day-29] R语言 - 分群其他演算法 ( Clustering other Algorithms )
>>: [区块链&DAPP介绍 Day21] contract 案例3 - 比大小下注游戏
09-15-2021 本章内容 pages意想不到的用途! 每个页面都是以pages作为基准路径 动...
设定基本段落样式,字体大小、行距及行距设定方式以及嵌入google font方式 设定基本字体 f...
一、前言 因为网页应用程序不断扩大、开发模式慢慢地被模组化设计取代,近期诞生了 Webpack,...
虽然是写C2 Server, 但实际上我们并不是真的要从这个Server发送指令出去, 我们只是要让...
在制作专案时,大多都是与他人共同协作,当一起开发的人越来越多时,就更需要有一套规则或模式来进行合作,...