這段時間做了一個用於初學者學習人臉識別系統的程式,在上程式碼時,先給說說事前準備:
首先我們需要一個OpenCV的一個haarcascade_frontalface_default.xml檔案,只要去GitHub上面即可下載:https://github.com/opencv/opencv
點選Code,選擇Download ZIP,下載後解壓在目錄下opencv-4.x\data\haarcascades中可以找到haarcascade_frontalface_default.xml,這個時候將這個檔案複製到你的工程目錄下。
第二個要準備的檔案是:lfw-deepfunneled,這個檔案在網站中下載:https://vis-www.cs.umass.edu/lfw/#download
進入網站後下拉找到Download the database: ,然後在這個模組中找到All images aligned with deep funneling,點選下載後,將壓縮包解壓到工程目錄下即可。
然後建立一個模型訓練的py檔案,程式碼如下:
import os
import numpy as np
import cv2
from matplotlib import pyplot as plt
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report, confusion_matrix
from joblib import dump
# 設定資料集路徑
lfw_home = 'D:/Pythonxiangmu/Python/renlian/lfw-deepfunneled' # 替換為實際路徑
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
# 函式:從目錄載入影像並提取人臉區域
def load_images_and_labels(directory):
images = []
labels = []
for label in sorted(os.listdir(directory)):
if not os.path.isdir(os.path.join(directory, label)):
continue
for img_path in os.listdir(os.path.join(directory, label)):
img = cv2.imread(os.path.join(directory, label, img_path), cv2.IMREAD_GRAYSCALE)
faces = face_cascade.detectMultiScale(img, scaleFactor=1.1, minNeighbors=5)
if len(faces) > 0:
for (x, y, w, h) in faces:
face_img = img[y:y + h, x:x + w]
face_img_resized = cv2.resize(face_img, (130, 195)) # 保持與應用程式碼一致
images.append(face_img_resized.flatten())
labels.append(label)
return np.array(images), np.array(labels)
def train_face_recognition_model(dataset_path):
# 載入影像和標籤
X, labels = load_images_and_labels(dataset_path)
# 資料集劃分
X_train, X_test, y_train, y_test = train_test_split(X, labels, test_size=0.25, random_state=42)
# 特徵縮放
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# PCA降維
n_components = 150 # 選擇合適的主成分數
pca = PCA(n_components=n_components, whiten=True)
X_train_pca = pca.fit_transform(X_train_scaled)
X_test_pca = pca.transform(X_test_scaled)
# 訓練邏輯迴歸模型
clf = LogisticRegression(C=1e5)
clf.fit(X_train_pca, y_train)
# 預測與評估
y_pred = clf.predict(X_test_pca)
print("Classification Report:")
print(classification_report(y_test, y_pred))
print("Confusion Matrix:")
print(confusion_matrix(y_test, y_pred))
# Eigenfaces進行視覺化(可選)
n_components_to_show = 10
"""視覺化前n個Eigenfaces"""
eigenfaces = pca.components_
eigenface_titles = ["Eigenface %d" % i for i in range(1, n_components_to_show + 1)]
# 選擇前n個Eigenfaces進行視覺化
for i in range(n_components_to_show):
eigenface = eigenfaces[i].reshape(195, 130) # 根據之前調整的尺寸進行重塑
plt.subplot(2, 5, i + 1)
plt.imshow(eigenface, cmap='gray')
plt.title(eigenface_titles[i])
plt.axis('off') # 不顯示座標軸
plt.show()
# 儲存模型與前處理器
dump(clf, 'model.pkl')
dump(scaler, 'scaler.pkl')
dump(pca, 'pca.pkl')
# 呼叫函式以執行訓練流程
train_face_recognition_model(lfw_home)
執行結束後,就會在你的工程目錄下建立三個訓練好的pkl檔案。
然後再建立一個人臉識別用的py檔案,程式碼如下:
import os
from tkinter import Tk, Label, messagebox
import cv2
import joblib
import numpy as np
from PIL import Image, ImageTk
# 載入預先訓練好的LogisticRegression模型,用於後續的人臉識別
model = joblib.load('model.pkl')
# 載入特徵縮放器,用於標準化輸入資料,提高模型識別效能
scaler = joblib.load('scaler.pkl')
# 載入PCA模型,用於降維處理,減少計算複雜度並去除噪聲
pca = joblib.load('pca.pkl')
# 定義函式:從給定路徑載入參考照片並提取其面部特徵
def load_reference_image(reference_path):
# 使用OpenCV讀取灰度影像作為參考照片
reference_image = cv2.imread(reference_path, cv2.IMREAD_GRAYSCALE)
# 利用預設的人臉檢測器檢測參考照片中的人臉
reference_faces = face_cascade.detectMultiScale(reference_image)
# 確保至少檢測到一張人臉,否則丟擲錯誤
if len(reference_faces) == 0:
raise ValueError("No face detected in reference image.")
# 獲取檢測到的第一張人臉區域
reference_face_roi = reference_image[
reference_faces[0][1]:reference_faces[0][1] + reference_faces[0][3],
reference_faces[0][0]:reference_faces[0][0] + reference_faces[0][2]
]
# 對提取的參考人臉區域進一步預處理,準備用於模型識別
preprocessed_reference_face = preprocess_face(reference_face_roi)
# 返回預處理後的面部特徵資料
return preprocessed_reference_face
# 定義函式:預處理輸入的人臉影像,以便用於模型識別
def preprocess_face(face_image):
# 確保影像尺寸與訓練時一致(130x195)
face_image_resized = cv2.resize(face_image, (130, 195))
# 影像資料展平
img_flattened = face_image_resized.flatten() # 調整尺寸後,直接展平
# 特徵縮放
img_scaled = scaler.transform(img_flattened.reshape(1, -1))
# PCA降維
img_pca = pca.transform(img_scaled)
# 使用訓練好的模型進行預測
return img_pca
# 定義函式:識別影片流中的臉部並判斷是否為目標人物
def recognize_faces(frame):
# 將影片幀轉換為灰度影像,便於人臉檢測
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 使用預定義的人臉級聯分類器檢測影像中的人臉
face_rects = face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 遍歷檢測到的每一個人臉區域
for (x, y, w, h) in face_rects:
# 提取人臉區域
face_roi = gray_frame[y:y + h, x:x + w]
# 對該人臉區域進行預處理
preprocessed_face = preprocess_face(face_roi)
# 使用模型預測該人臉屬於各個類別的機率
probabilities = model.predict_proba(preprocessed_face.reshape(1, -1))[0]
# 獲取最可能的預測類別
predicted_label = np.argmax(probabilities)
# 若預測類別與目標人物標籤匹配,則認為識別到了目標人物
if predicted_label == target_person_label:
return True
# 若未識別到目標人物,則返回False
return False
# 載入OpenCV預訓練的人臉檢測模型(基於Haar特徵的級聯分類器)
base_dir = r"D:\Pythonxiangmu\Python\renlian"
xml_path = os.path.join(base_dir, "haarcascade_frontalface_default.xml")
face_cascade = cv2.CascadeClassifier(xml_path)
# 設定目標人物在模型中的標籤假設
target_person_label = 0
# 初始化Tkinter圖形介面,用於展示影片流及識別結果
root = Tk()
root.title("Face Recognition System")
root.geometry("800x600")
# 建立一個Label控制元件用於動態顯示影片幀
label = Label(root)
label.pack(fill="both", expand=True)
# 載入並預處理參考照片,獲取其特徵編碼
photo_path = os.path.join(base_dir, "zhaopian.jpg")
reference_face_encoding = load_reference_image(photo_path)
# 定義影片流展示的回撥函式,持續更新顯示內容並執行人臉識別
def show_frame():
# 從攝像頭讀取一幀影像
ret, frame = cap.read()
if ret: # 確保成功讀取到幀
# 嘗試識別當前幀中的人臉
is_recognized = recognize_faces(frame)
# 若識別到目標人物,彈出提示框
if is_recognized:
messagebox.showinfo("Recognition Result", "Face recognized!")
# 轉換影像色彩空間以適應Tkinter顯示,並調整尺寸
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
pil_image = Image.fromarray(rgb_frame)
resized_image = pil_image.resize((root.winfo_width(), root.winfo_height()))
# 轉換為Tkinter相容的影像格式並更新顯示
tk_image = ImageTk.PhotoImage(image=resized_image)
label.config(image=tk_image)
label.image = tk_image # 防止影像物件被提前釋放
# 定時呼叫自身以實現連續更新
root.after(1, show_frame)
# 初始化攝像頭裝置
cap = cv2.VideoCapture(0)
# 啟動影片流的顯示迴圈
show_frame()
# 執行Tkinter事件迴圈
root.mainloop()
# 關閉攝像頭資源
cap.release()
執行後就開始人臉識別,這樣就完成啦!
注意,程式碼中的所有的路徑都應該改成自己的路徑!其中的畫素可以修改,但是要注意訓練指令碼要和識別指令碼的畫素一致,否則會報錯!
如果有什麼問題歡迎在評論區提問,也可以發個人郵箱:linyuanda@linyuanda.com