OpenCV 人臉識別
本教程將討論使用 OpenCV 中的 face_recognition
庫識別影象中存在的人臉。
在 OpenCV 中使用 face_recognition
庫識別影象中的人臉
人臉識別用於識別影象或視訊中存在的人臉。例如,Facebook 使用面部識別來標記帖子中的人。
如果我們在圖片中標記我們的朋友,Facebook 演算法將識別該人的姓名,並在我們下次上傳該人的照片時自動標記他。我們還可以使用 face_recognition
庫構建類似的演算法。
人臉識別庫分多個步驟工作以識別人臉。第一步,我們需要傳遞已知人的圖片來訓練模型,庫將使用 HOG
或定向梯度直方圖來查詢給定影象中存在的人臉。
在人臉識別中,我們只需要一張人臉的圖片,不需要任何其他資料,因為資料量大,會使演算法變得更慢、更復雜。
HOG
演算法將每個畫素與其相鄰畫素進行比較,以找到強度方向,並在強度級別增加的方向上用梯度標記它。
該演算法已經有一張平均人臉的梯度影象。該演算法將梯度影象與人臉的已知梯度進行比較,以確定影象的哪個部分包含人臉。
例如,讓我們使用人臉識別庫的 face_locations()
函式查詢影象中存在的人臉。請參閱下面的程式碼。
import cv2
import dlib
import face_recognition
img = cv2.imread("tom1.jpg")
known_img = face_recognition.load_image_file("tom1.jpg")
loc = face_recognition.face_locations(known_img)
cv2.rectangle(img, (loc[0][0], loc[0][3]), (loc[0][1], loc[0][2]), (255, 0, 0), 3)
print(loc)
cv2.imshow("locations", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
輸出:
正如我們在上面的輸出中看到的,在上面的影象中使用 HOG
演算法檢測到人臉。我們使用兩個函式匯入了相同的影象,因為 imread()
函式讀取 BGR 色標中的影象,而 load_image_file()
函式讀取 RGB 顏色空間中的影象。
人臉識別庫使用 RGB 影象,而 OpenCV 使用 BGR 影象,我們在上面的程式碼中都需要。我們使用 OpenCV 的 rectangle()
函式在檢測到的面部周圍繪製一個矩形。
face_locations()
函式返回矩形的點或角位置,我們可以在 rectangle()
函式中使用它們來繪製矩形。face_locations()
函式還有兩個可選引數,number_of_times_to_upsample
和 batch_size
。
計算機將影象儲存為數字陣列,因此如果人臉影象被旋轉或影象中的光照發生變化,即使是同一張臉,計算機也會將其視為另一張影象。該庫在第二步中使用人臉界標估計解決了這個問題。
在人臉界標估計中,我們使用機器學習演算法來獲得 68 個對人臉識別很重要的面部界標,例如眼睛和鼻子周圍的界標。
使用這些地標,我們可以旋轉和共享我們的影象,以建立一個完美居中的影象,眼睛和鼻子位於影象的中心。
我們不必擔心面部的方向或角度。第三步,我們必須訓練一個模型來進行預測。
我們不能簡單地將未知影象與所有已知影象進行比較來識別人,因為這需要時間。
我們可以使用每張影象的一些特徵,例如耳朵、眼睛和鼻子大小之間的距離,並將它們與未知的人臉影象進行比較,而不是使用整個人臉影象。
但是,我們不知道哪些特徵最適合識別人臉。因此,我們將使用深度卷積神經網路從每個已知影象中找到 128 個測量值或面部特徵。
為了訓練模型,我們必須提供兩張已知人的影象和一張未知人的影象,神經網路將通過比較給定的影象來找到 128 個測量值。訓練一個模型也需要很多時間,因此人臉庫使用 OpenFace
的預訓練模型來獲取所有已知人臉的 128 個測量值。
在最後一步,我們必須使用分類器來檢查未知人臉是否與任何已知人臉相似。人臉識別庫使用 SVM
或空間向量機分類器進行預測。
例如,讓我們使用 Tom Cruise 的一張影象進行訓練,另一張影象用於測試。請參閱下面的程式碼。
import cv2
import dlib
import face_recognition
known_img = face_recognition.load_image_file("tom1.jpg")
unknown_img = face_recognition.load_image_file("tom2.jpg")
known_en = face_recognition.face_encodings(known_img)[0]
unknown_en = face_recognition.face_encodings(unknown_img)[0]
result = face_recognition.compare_faces([known_en], unknown_en)
print(result)
cv2.imshow("Known Image", known_img)
cv2.imshow("Un_Known Image", unknown_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
輸出:
[True]
輸出結果為真
,這意味著未知影象是湯姆克魯斯。我們在上面的程式碼中使用了人臉識別庫的 face_encodings()
函式來查詢 128 個測量值。
face_encodings()
函式的第一個引數是輸入影象。第二個引數 known_face_locations
是可選的,它用於設定每個人臉的邊界框,預設情況下,它的值設定為 none
。
第三個引數 num_jitters
也是可選的,它用於設定用於查詢編碼的重取樣值,預設設定為 1
。第四個引數 model
也是可選的,用於設定用於查詢編碼的模型型別,預設設定為 small
。
小模型速度快但精度較低,大模型速度慢但精度更高。我們使用 compare_faces()
將未知面孔與已知面孔進行比較。
compare_faces()
函式的第一個引數包含已知人臉的編碼,第二個引數包含未知人臉的編碼。第三個引數 tolerance
是可選的,用於設定面之間的距離,預設情況下,其值設定為 0.6
。
在 OpenCV 中使用 putText()
函式將文字放的影象頂部
我們還可以使用 OpenCV 的 putText()
函式在影象上放置與已知人臉相似的文字。例如,讓我們使用 Tom Cruise 影象來訓練模型,然後使用 Dwayne Johnson 的影象來測試模型。
請參閱下面的程式碼。
import cv2
import dlib
import face_recognition
img = cv2.imread("rock1.jpg")
known_img = face_recognition.load_image_file("tom2.jpg")
unknown_img = face_recognition.load_image_file("rock1.jpg")
known_en = face_recognition.face_encodings(known_img)[0]
unknown_en = face_recognition.face_encodings(unknown_img)[0]
result = face_recognition.compare_faces([known_en], unknown_en)
loc = face_recognition.face_locations(unknown_img)
cv2.rectangle(img, (loc[0][0], loc[0][3]), (loc[0][1], loc[0][2]), (255, 0, 0), 3)
if result[0]:
text = "Tom Cruise"
else:
text = "Unknown"
cv2.putText(
img,
text,
(loc[0][0], loc[0][3] - 20),
cv2.FONT_HERSHEY_SIMPLEX,
1.2,
(0, 0, 255),
2,
cv2.LINE_AA,
)
cv2.imshow("locations", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
輸出:
上面這張臉不像湯姆克魯斯的臉。我們還可以使用不同人的多張影象來訓練模型,我們還可以在視訊中找到人臉。
對於視訊,我們必須單獨處理每一幀。檢視此連結瞭解有關人臉識別庫的更多詳細資訊。