一、OpenCV簡單介紹
在實現(xiàn)人臉識別之前截粗,我們先簡單了解一下OpenCv的一些基本操作疫稿。在此之前,我們需要先安裝OpenCv粉臊,我們使用pip安裝:
pip install opencv-python
另外我們還需要另外一個模塊:
pip install opencv-contrib-python
接下來我們就可以學(xué)習(xí)OpenCv了垢夹。
1.1、OpenCv操作圖像
我們來簡單讀取一個圖像维费,并將該圖像顯示:
# 導(dǎo)入模塊
import cv2
# 讀取圖片
im = cv2.imread('1.jpg')
# 顯示圖片果元,該方法只會顯示一瞬間。(第一個參數(shù)為窗口名稱犀盟,第二個參數(shù)為ndarray對象)
cv2.imshow('im', im)
# 等待鍵盤輸入而晒,傳入毫秒值,當傳入0時表示無限等待阅畴。(imshow配合該方法可以讓界面一直顯示)
cv2.waitKey(0)
# 因為OpenCv是用C/C++寫的倡怎,所以需要釋放內(nèi)存
cv2.destroyAllWindows()
上述代碼就實現(xiàn)了最簡單的讀取并顯示圖像的操作了。
1.2贱枣、灰度轉(zhuǎn)換
灰度就是使用黑色調(diào)表示物體监署,即用黑色為基準色,不同的飽和度的黑色來顯示圖像纽哥。 灰度轉(zhuǎn)換就是將圖片轉(zhuǎn)換成黑白圖像钠乏。因為我們在人臉識別時,灰度圖像便于識別春塌,所以我們先來了解一下晓避。用OpenCv實現(xiàn)灰度轉(zhuǎn)換很簡單:
import cv2
# 讀取圖像
im = cv2.imread('1.jpg')
# 灰度轉(zhuǎn)換(第一個參數(shù)為ndarray對象,第二個參數(shù)為cv2中的常量)只壳,返回一個ndarray對象
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 將grey保存
cv2.imwrite('grey.jpg', grey)
# 顯示灰度轉(zhuǎn)換后的圖像
cv2.imshow('grey', grey)
# 等待鍵盤輸入
cv2.waitKey(0)
# 銷毀窗口
cv2.destroyAllWindows()
效果如下:
1.3俏拱、繪制圖形
我們后續(xù)在檢測人臉的時候,我們會繪制圖形吼句,將人臉框起來锅必。圖形的繪制也非常簡單,我們看如下代碼:
import cv2
# 讀取圖像
im = cv2.imread('1.jpg')
# 在圖像im上繪制矩形
"""
第一個參數(shù)為ndarray對象
第二個參數(shù)為左上角的坐標(x1, y1)
第三個參數(shù)為右下角的坐標(x2, y2)
第四個參數(shù)為顏色值惕艳,其順序不同于我們之前的搞隐,使用的是BGR
第五個參數(shù)為線條寬度
"""
cv2.rectangle(im, (0, 0), (200, 200), (255, 255, 0), 2)
# 顯示圖像
cv2.imshow('im', im)
# 等待輸入
cv2.waitKey(0)
# 銷毀窗口
cv2.destroyAllWindows()
對比圖如下:
了解上面知識后分蓖,我們就可以進入下一步的學(xué)習(xí)了。
二尔许、人臉檢測
2.1、獲取特征數(shù)據(jù)
開始人類檢測之前终娃,我們要先獲取一個特征數(shù)據(jù)味廊。我們先去官網(wǎng),看到如下界面:
點擊相應(yīng)的下載后棠耕,雙擊安裝就可以了余佛。我們進入D:\CodeField\OpenCv\opencv\sources\data\haarcascades,前面為你opencv的安裝目錄窍荧。進入該文件夾后辉巡,里面全是特征文件,我們一般選用haarcascade_frontalface_default.xml蕊退。
2.1郊楣、檢測人臉
我們可以把特征文件復(fù)制到我們項目下,也可以直接用絕對路徑引用瓤荔。我們檢測人臉需要一個cv2.CascadeClassifier對象净蚤,該對象可以用來檢測人臉。代碼如下:
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
其中输硝,傳入?yún)?shù)為特征文件的路徑今瀑。我們可以選擇相對路徑,也可以選擇絕對路徑点把。完整人類檢測代碼如下:
import cv2
# 加載特征數(shù)據(jù)
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:
# 在人臉區(qū)域繪制矩形
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張人臉的左上角坐標郎逃、臉的寬哥童、臉的高。檢測效果如下:
不過有時會有一些誤差褒翰,大多數(shù)清晰人臉可以正常檢測到如蚜。
三、人臉識別
上面的內(nèi)容我們已經(jīng)說了人臉檢測的實現(xiàn)影暴,那人臉識別和人臉檢測有什么區(qū)別呢错邦?它們的區(qū)別在于,人臉檢測是要確定一張圖像里面有沒有人臉型宙,而人臉識別則是要確定圖像中的人臉是誰撬呢。不過要確定是誰之前,我們需要先見過人臉的主人妆兑,這就需要我們訓(xùn)練數(shù)據(jù)了魂拦。
3.1毛仪、訓(xùn)練數(shù)據(jù)
訓(xùn)練數(shù)據(jù)主要有兩個部分,人臉信息和標簽芯勘,其中標簽為int列表箱靴。我在目錄gtx中準備了50來張鋼鐵俠圖片,為了方便獲取標簽荷愕,我們先編寫如下代碼:
import os
path = "./gtx/"
# 獲取文件列表
paths = os.listdir(path)
i = 0 # 循環(huán)變量
for file in paths:
i += 1
# 將文件重命名
os.rename(path+file, path + str(i) + str(1) + ".jpg")
這段代碼就是遍歷當前目錄下gtx文件夾下的圖片衡怀,將圖片名稱改為數(shù)字+1+.jpg格式。
上面是我用爬蟲爬取的一些圖片安疗,我們將這些使用上述代碼轉(zhuǎn)換成數(shù)字+1+.jpg格式抛杨,我們把1做為小羅伯特唐尼的標簽,我們可以繼續(xù)多把其他人的人臉改為數(shù)字+2+.jpg格式荐类,這樣就可以做到區(qū)分怖现。不過上述代碼有一個問題,即當我們遍歷到第四個圖片時玉罐,名稱需要改為41.jpg屈嗤,而在我的文件夾中已經(jīng)存在41.jpg,所以會產(chǎn)生錯誤吊输。我們將代碼改為如下:
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)
# 當發(fā)生異常時恢共,直接跳過
continue
準備好圖像后,我們就可以開始訓(xùn)練數(shù)據(jù)了璧亚,訓(xùn)練數(shù)據(jù)代碼如下:
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)
# 轉(zhuǎn)換灰度
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 讀取人臉數(shù)據(jù)
face = face_detector.detectMultiScale(grey)
for x, y, w, h in face:
# 設(shè)置標簽讨韭,分離文件名稱
lables.append(int(file.split('.')[0]))
# 設(shè)置人臉數(shù)據(jù)
faces.append(grey[y:y+h, x:x+w])
return faces, lables
# 調(diào)用方法獲取人臉信息及標簽
faces, labels = getFacesAndLabels()
# 獲取訓(xùn)練對象
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 訓(xùn)練數(shù)據(jù)
recognizer.train(faces, numpy.array(labels))
# 保存訓(xùn)練數(shù)據(jù)
recognizer.write('./trainer/trainer.yml')
在上面代碼中,我們上面的并沒有對文件名稱中的最后一個數(shù)字1進行區(qū)分癣蟋,后續(xù)會使用到透硝。關(guān)于訓(xùn)練數(shù)據(jù),大家可以多準備一些人物和圖片疯搅。
3.2濒生、人臉識別
我們訓(xùn)練完數(shù)據(jù)后,就可以進行人臉識別了幔欧。在識別之前我們先加載訓(xùn)練數(shù)據(jù)罪治,然后就是基本的人類檢測步驟。最后我們調(diào)用predict方法進行人臉識別礁蔗,在訓(xùn)練數(shù)據(jù)中匹配人物觉义。
import cv2
# 加載訓(xùn)練數(shù)據(jù)集
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:
# 返回人臉標簽和可信度,可信度數(shù)值越低浴井,可信度越高(用詞不當晒骇,不要在意)
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("未匹配到數(shù)據(jù)")
cv2.imshow('im', im)
cv2.waitKey(0)
# 銷毀窗口
cv2.destroyAllWindows()
上述代碼中洪囤,我們用標簽label%10徒坡,可以獲得文件最后一個數(shù)字,這樣就可以達到區(qū)分人物的作用瘤缩,我們用如下圖片進行測試喇完。
輸出結(jié)果如下:
小羅伯特唐尼
算是成功了,多次測試后剥啤,發(fā)現(xiàn)準備率方面比較中規(guī)中矩锦溪。大家可以嘗試多準備寫圖片用來訓(xùn)練,從而提高準確率铐殃。代碼已上傳GitHub:https://github.com/IronSpiderMan/GtxFaceDetector