計算機視覺(一):人臉檢測和識別
1 - 引言
之前我們學習了機器學習和數字影象處理的相關知識,瞭解了基本的概念理論和OpenCV和TensorFlow框架的使用,現在我們可以結合這些知識與工具寫出屬於我們自己的計算機視覺專案,本文主要介紹瞭如何使用OpenCV提供的函式來構建一個人臉識別和檢測的應用
2 - Haar級聯的概念
我們知道提取出影象資料的細節特徵對產生穩定分類結果和跟蹤結果很有用,兩個影象的相似程度可以通過他們對應特徵的歐氏距離來度量。
類Haar特徵是一種用於實現實時人臉跟蹤的特徵。文獻《Robust Real-time Face Detection》首次採用這種特徵來進行人臉檢測
OpenCV的原始碼中data資料夾中包含了這種特徵的XML檔案,可以用來檢測靜止的影象、視訊和攝像頭中的人臉
我們可以利用這些特徵創造自己的級聯,並訓練這些級聯來檢測各種物件
3 - 使用OpenCV進行人臉檢測
3.1 - 靜態影象中的人臉檢測
人臉檢測首先是載入影象並檢測人臉,這也是最基本的一步,我們在圖片的人臉處繪製矩形框
首先在專案中建立cascades資料夾,把特徵XML檔案放入cascades資料夾中。使用Python實現:
import cv2 filename = 'images/6.jpg' def detect(filename): """ 函式:face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml') 該函式聲明瞭face_cascade變數,該變數為CascadeClassifier物件,它負責人臉檢測 函式:faces = face_cascade.detectMultiScale(gray,1.3,5) 傳遞的引數是scaleFactor和minNeighbors,它們分別表示人臉檢測過程中每次迭代時影象的 壓縮率以及每個人臉矩形保留鄰近數目的最小值 返回值為人臉矩形陣列 函式:img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) 通過座標來繪製矩形(x,y表示左上角的座標,w,h表示人臉矩形的寬度和高度) """ face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml') img = cv2.imread(filename) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray,1.3,5) for (x,y,w,h) in faces: img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) cv2.namedWindow('Vikings Detected!!') cv2.imshow('Vikings Detected!!', img) cv2.waitKey(0) detect(filename)
下面識別索爾維會議中的人臉(有兩個人沒有檢測出來,可見光用使用face_cascade一個特徵來識別人臉還是不太行啊)
3.2 - 視訊中的人臉檢測
在視訊的幀上重複這個過程就能完成視訊中的人臉檢測
import cv2 import sys def detect(): """ 定義兩個特徵:面部特徵和眼部特徵 """ face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml') eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_eye.xml') camera = cv2.VideoCapture(0) #0表示使用第一個攝像頭 """ 接下來捕獲幀,read()函式會返回兩個值:第一個值為布林值,用來表明是否成功讀取幀,第二個值為幀本身。捕捉到幀後,將其 轉換成灰度影象 """ while (True): ret, frame = camera.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5) for (x, y, w, h) in faces: # 返回的x,y代表roi區域的左上角座標,w,h代表寬度和高度 img = cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2) roi_gray = gray[y:y + h, x:x + w] eyes = eye_cascade.detectMultiScale(roi_gray, 1.03, 5, 0, (40, 40)) for (ex, ey, ew, eh) in eyes: cv2.rectangle(img, (x + ex, y + ey), (x + ex + ew, y + ey + eh), (0, 255, 0), 2) cv2.imshow("camera", frame) key = cv2.waitKey(30) & 0xff #按ESC退出 if key == 27: sys.exit() if __name__ == "__main__": detect()
通過在攝像頭中識別的效果
4 - 人臉識別
我們在實現人臉檢測,它是人臉識別的基礎,識別和檢測的區別在於一個程式能否識別出給定影象或視訊中的人臉。實現這一目標的方法之一是用一系列分好類的影象(人臉資料庫)來“訓練”程式,並基於這些影象來進行識別
在這裡,我們可以利用視訊操作來生成屬於自己的面部資料
4.1 生成人臉識別資料
樣本影象滿足
- 影象是灰度格式,字尾名為.pgm
- 影象形狀為正方形
- 影象大小要一樣(這裡使用200x200)
import cv2
import sys
def detect():
"""
定義兩個特徵:面部特徵和眼部特徵
"""
face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_eye.xml')
camera = cv2.VideoCapture(0) #0表示使用第一個攝像頭
count = 0
"""
接下來捕獲幀,read()函式會返回兩個值:第一個值為布林值,用來表明是否成功讀取幀,第二個值為幀本身。捕捉到幀後,將其
轉換成灰度影象
"""
while (True):
ret, frame = camera.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x, y, w, h) in faces: # 返回的x,y代表roi區域的左上角座標,w,h代表寬度和高度
img = cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
f = cv2.resize(gray[y:y+h, x:x+w],(200,200))
cv2.imwrite('./data/at/jm/%s.pgm' % str(count),f)
count += 1
cv2.imshow("camera", frame)
key = cv2.waitKey(30) & 0xff #按ESC退出
if key == 27:
sys.exit()
if __name__ == "__main__":
detect()
這樣就將資料儲存到資料夾中
4.2 - 人臉識別
Opencv提供的三種演算法:
- Eigenfaces
通過PCA來處理,分析訓練集的主成分,計算訓練集相對於資料庫的發散程度,並輸出一個值,值越小,表面人臉資料庫和檢測到的人臉之間的差別就越小; - Fisherfaces
PCA衍生並發展起來的概念,採用更復雜的邏輯,比Eigenfaces 更容易得到準確的效果 - Local Binary Pattern Histogram(LBPH)
將檢測到的人臉分成小單元,並將其與模型中的對應單元進行比較,對每個區域的匹配值產生一個直方圖。
這些方法都有類似的過程,即都使用了分好類的訓練資料集來訓練,並從兩方面來確認:是否識別到目標;目標真正被識別到的置信度的度量,這也稱為置信度評分
import cv2,os,sys
import numpy as np
def read_images(path, sz = None):
c = 0
X, y = [], []
for dirname, dirnames, filenames in os.walk(path):
for subdirname in dirnames:
subject_path = os.path.join(dirname, subdirname)
for filename in os.listdir(subject_path):
try:
if not filename.endswith('.pgm'):
continue
filepath = os.path.join(subject_path, filename)
im = cv2.imread(filepath, cv2.IMREAD_GRAYSCALE)
if sz is not None:
im = cv2.resize(im,(200,200))
X.append(np.asarray(im, dtype=np.uint8))
y.append(c)
except:
print("Unexpected error:",sys.exc_info()[0])
c = c + 1
return [X, y]
def face_rec(img_path):
names = ['Leon']
[X,y] = read_images(img_path)
y = np.asarray(y, dtype=np.int32)
model = cv2.face.EigenFaceRecognizer_create()
model.train(np.asarray(X), np.asarray(y))
camera = cv2.VideoCapture(0)
face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
while (True):
read, img = camera.read()
faces = face_cascade.detectMultiScale(img, 1.3, 5)
for (x, y, w, h) in faces:
img = cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
roi = gray[x: x+w, y: y+h]
try:
roi = cv2.resize(roi, (200, 200), interpolation=cv2.INTER_LINEAR)
params = model.predict(roi)
print("Label: %s, Confidence: %.2f" % (params[0], params[1]))
cv2.putText(img, names[params[0]], (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2)
except:
continue
cv2.imshow("camera", img)
if cv2.waitKey(1000 // 12) & 0xff == ord('q'):
break
cv2.destroyAllWindows()
if __name__ == "__main__":
face_rec('./data/at/') #人臉資料路徑img_path
可以把人臉檢測出來並且識別出是誰的人臉
置信度評價: