一、OpenCV簡單介紹
在實現人臉識別之前,我們先簡單瞭解一下OpenCv的一些基本操作。在此之前,我們需要先安裝OpenCv,我們使用pip安裝:
pip install opencv-python
另外我們還需要另外一個模塊:
pip install opencv-contrib-python
接下來我們就可以學習OpenCv了。
1.1、OpenCv操作圖像
我們來簡單讀取一個圖像,並將該圖像顯示:
# 導入模塊
import cv2
# 讀取圖片
im = cv2.imread('1.jpg')
# 顯示圖片,該方法只會顯示一瞬間。(第一個參數爲窗口名稱,第二個參數爲ndarray對象)
cv2.imshow('im', im)
# 等待鍵盤輸入,傳入毫秒值,當傳入0時表示無限等待。(imshow配合該方法可以讓界面一直顯示)
cv2.waitKey(0)
# 因爲OpenCv是用C/C++寫的,所以需要釋放內存
cv2.destroyAllWindows()
上述代碼就實現了最簡單的讀取並顯示圖像的操作了。
1.2、灰度轉換
灰度就是使用黑色調錶示物體,即用黑色爲基準色,不同的飽和度的黑色來顯示圖像。 灰度轉換就是將圖片轉換成黑白圖像。因爲我們在人臉識別時,灰度圖像便於識別,所以我們先來了解一下。用OpenCv實現灰度轉換很簡單:
import cv2
# 讀取圖像
im = cv2.imread('1.jpg')
# 灰度轉換(第一個參數爲ndarray對象,第二個參數爲cv2中的常量),返回一個ndarray對象
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 將grey保存
cv2.imwrite('grey.jpg', grey)
# 顯示灰度轉換後的圖像
cv2.imshow('grey', grey)
# 等待鍵盤輸入
cv2.waitKey(0)
# 銷燬窗口
cv2.destroyAllWindows()
效果如下:
1.3、繪製圖形
我們後續在檢測人臉的時候,我們會繪製圖形,將人臉框起來。圖形的繪製也非常簡單,我們看如下代碼:
import cv2
# 讀取圖像
im = cv2.imread('1.jpg')
# 在圖像im上繪製矩形
"""
第一個參數爲ndarray對象
第二個參數爲左上角的座標(x1, y1)
第三個參數爲右下角的座標(x2, y2)
第四個參數爲顏色值,其順序不同於我們之前的,使用的是BGR
第五個參數爲線條寬度
"""
cv2.rectangle(im, (0, 0), (200, 200), (255, 255, 0), 2)
# 顯示圖像
cv2.imshow('im', im)
# 等待輸入
cv2.waitKey(0)
# 銷燬窗口
cv2.destroyAllWindows()
對比圖如下:
瞭解上面知識後,我們就可以進入下一步的學習了。
二、人臉檢測
2.1、獲取特徵數據
開始人類檢測之前,我們要先獲取一個特徵數據。我們先去官網,看到如下界面:
點擊相應的下載後,雙擊安裝就可以了。我們進入D:\CodeField\OpenCv\opencv\sources\data\haarcascades,前面爲你opencv的安裝目錄。進入該文件夾後,裏面全是特徵文件,我們一般選用haarcascade_frontalface_default.xml。
2.1、檢測人臉
我們可以把特徵文件複製到我們項目下,也可以直接用絕對路徑引用。我們檢測人臉需要一個cv2.CascadeClassifier對象,該對象可以用來檢測人臉。代碼如下:
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
其中,傳入參數爲特徵文件的路徑。我們可以選擇相對路徑,也可以選擇絕對路徑。完整人類檢測代碼如下:
import cv2
# 加載特徵數據
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 讀取圖片
im = cv2.imread('1.jpg')
# 檢測人臉,返回人臉的位置信息
faces = face_detector.detectMultiScale(im)
# 遍歷人臉
for x, y, w, h in faces:
# 在人臉區域繪製矩形
cv2.rectangle(im, (x, y), (x+w, y+h), (255, 255, 0), 2)
# 顯示圖像
cv2.imshow('im', im)
cv2.waitKey(0)
cv2.destroyAllWindows()
其中detectMultiScale方法返回一個ndarray對象,這個對象保存了n張人臉的左上角座標、臉的寬、臉的高。檢測效果如下:
不過有時會有一些誤差,大多數清晰人臉可以正常檢測到。
三、人臉識別
上面的內容我們已經說了人臉檢測的實現,那人臉識別和人臉檢測有什麼區別呢?它們的區別在於,人臉檢測是要確定一張圖像裏面有沒有人臉,而人臉識別則是要確定圖像中的人臉是誰。不過要確定是誰之前,我們需要先見過人臉的主人,這就需要我們訓練數據了。
3.1、訓練數據
訓練數據主要有兩個部分,人臉信息和標籤,其中標籤爲int列表。我在目錄gtx中準備了50來張鋼鐵俠圖片,爲了方便獲取標籤,我們先編寫如下代碼:
import os
path = "./gtx/"
# 獲取文件列表
paths = os.listdir(path)
i = 0 # 循環變量
for file in paths:
i += 1
# 將文件重命名
os.rename(path+file, path + str(i) + str(1) + ".jpg")
這段代碼就是遍歷當前目錄下gtx文件夾下的圖片,將圖片名稱改爲數字+1+.jpg格式。
上面是我用爬蟲爬取的一些圖片,我們將這些使用上述代碼轉換成數字+1+.jpg格式,我們把1做爲小羅伯特唐尼的標籤,我們可以繼續多把其他人的人臉改爲數字+2+.jpg格式,這樣就可以做到區分。不過上述代碼有一個問題,即當我們遍歷到第四個圖片時,名稱需要改爲41.jpg,而在我的文件夾中已經存在41.jpg,所以會產生錯誤。我們將代碼改爲如下:
import os
path = "./gtx/"
paths = os.listdir(path)
i = 0
for file in paths:
i += 1
try:
os.rename(path + file, path + str(i) + str(1) + ".jpg")
except Exception as e:
print(e)
# 當發生異常時,直接跳過
continue
準備好圖像後,我們就可以開始訓練數據了,訓練數據代碼如下:
import cv2
import os
import numpy
root_path = "./gtx/"
def getFacesAndLabels():
"""讀取圖片特徵和標籤"""
global root_path
faces = []
lables = []
# 獲取人臉檢測器
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 獲取圖片路徑
files = os.listdir(root_path)
for file in files:
path = root_path + file
# 讀取圖片
im = cv2.imread(path)
# 轉換灰度
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 讀取人臉數據
face = face_detector.detectMultiScale(grey)
for x, y, w, h in face:
# 設置標籤,分離文件名稱
lables.append(int(file.split('.')[0]))
# 設置人臉數據
faces.append(grey[y:y+h, x:x+w])
return faces, lables
# 調用方法獲取人臉信息及標籤
faces, labels = getFacesAndLabels()
# 獲取訓練對象
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 訓練數據
recognizer.train(faces, numpy.array(labels))
# 保存訓練數據
recognizer.write('./trainer/trainer.yml')
在上面代碼中,我們上面的並沒有對文件名稱中的最後一個數字1進行區分,後續會使用到。關於訓練數據,大家可以多準備一些人物和圖片。
3.2、人臉識別
我們訓練完數據後,就可以進行人臉識別了。在識別之前我們先加載訓練數據,然後就是基本的人類檢測步驟。最後我們調用predict方法進行人臉識別,在訓練數據中匹配人物。
import cv2
# 加載訓練數據集
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('./trainer/trainer.yml')
# 準備識別的圖片
im = cv2.imread('1.jpg')
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 檢測人臉
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
face = face_detector.detectMultiScale(grey)
for x, y, w, h in face:
# 返回人臉標籤和可信度,可信度數值越低,可信度越高(用詞不當,不要在意)
label, confidence = recognizer.predict(grey[y:y+h, x:x+w])
# 這裏將60作爲界限,當檢測檢測值爲60時,我們就確定人物
if confidence <= 60:
if label % 10 == 1:
print('小羅伯特唐尼')
elif lable % 10 == 2:
pass
else:
print("未匹配到數據")
cv2.imshow('im', im)
cv2.waitKey(0)
# 銷燬窗口
cv2.destroyAllWindows()
上述代碼中,我們用標籤label%10,可以獲得文件最後一個數字,這樣就可以達到區分人物的作用,我們用如下圖片進行測試。
輸出結果如下:
小羅伯特唐尼
算是成功了,多次測試後,發現準備率方面比較中規中矩。大家可以嘗試多準備寫圖片用來訓練,從而提高準確率。代碼已上傳GitHub:https://github.com/IronSpiderMan/GtxFaceDetector