第五章
人臉檢測和識別
Haar級聯
- Haar級聯具有
尺度不變性
(不同尺度的兩幅圖像也有相似特徵) - OpenCV的Haar級聯不具有
旋轉不變形
- 類Harr特徵是一種用於實現實時人臉跟蹤的特徵,每個類Haar特徵都描述了相鄰圖像區域的對比模式
- 圖像的特徵集合稱爲
級聯
獲取Harr級聯數據
- OpenCV源代碼的副本中文件夾:
data/haarcascades
包含了OpenCV所有人臉檢測的XML文件,可檢測圖像、視頻、攝像頭所得圖像的人臉(需要正面,直立的人臉圖像)
使用OpenCV人臉檢測
對圖片進行人臉檢測
import cv2
filename = './5_1.jpg'
def detect(filename):
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('Detected!')
cv2.imshow('Detected!',img)
cv2.waitKey(0)
detect(filename)
視頻中的人臉檢測
import cv2
def detect():
# 加載Haar級聯文件
face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_eye.xml')
camera = cv2.VideoCapture(0) # 初始化攝像頭
# 與靜態圖像的人臉檢測類似,視頻中對每一幀進行靜態圖像的人臉檢測
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:
cv2.rectangle( frame , (x,y) , (x+w,y+h) , (255,0,0) , 2 ) # 在源圖像中畫框
img = frame[y:y+h , x:x+w]
roi_gray = gray[y:y+h , x:x+w]
# 人臉檢測時,後兩個參數默認即可,但眼睛是一個比較小的人臉特徵,且鼻子等的隨機陰影都會產生假陽性
#通過限制對人眼搜索的最小尺寸40*40像素,可去除所有假陽性
eyes = eye_cascade.detectMultiScale( roi_gray , 1.03 , 5 , 0 , (40,40) )
for ( ex , ey , ew , eh ) in eyes:
cv2.rectangle( img , (ex,ey) , (ex+ew , ey+eh) , (0,255,0) , 2 ) # 人眼區域畫框
cv2.imshow("camera",frame)
if cv2.waitKey( 5 ) & 0xff == ord("q"): # 等待鍵盤事件(每5ms),q退出
break
camera.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
detect()
[注]:灰度圖像中進行人臉檢測,源圖像中畫框(涉及兩張圖片)
人臉識別
- OpenCV的三種人臉識別方法:
Eigenfaces
,Fisherfaces
,Local Binary Pattern Histogram(LBPH)
LBPH
是唯一允許模型樣本人臉和檢測到的人臉在形狀,大小可以不同的人臉識別算法
生成人臉識別數據
- 打開攝像頭獲取人臉並存儲爲.pgm格式
import cv2
def generate():
face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
#eye_cascade = cv2.CascadeClassifier('/cascades/haarcascade_eye.xml')
camera = cv2.VideoCapture(0)
count = 0
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:
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)
if cv2.waitKey( 1000 // 12 ) & 0xFF == ord("q") :
break
camera.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
generate()
生成.csv文件
- 基於逗號分隔值的(.CSV)文件,根據ID記錄樣本圖像路徑(最後的數字表示ID)
def generate_csv(id=0): #在csv文件中加入用戶id條目
count = 0
fout = open('a.csv', 'w', encoding='utf-8')
for i in range(21):
fout.write('jm/%s.pgm;'%str(i))
fout.write('%s'%str(id))
fout.write('\n')
if __name__ == "__main__":
generate_csv()
加載數據識別人臉
- 基於Eigenfaces的人臉識別
- 書中的實現未用到.csv,所有就自己改動了一下,但是寫的比較僵硬。
- 先給出根目錄,然後加上
.csv
文件中的每個.pgm
圖像的路徑,得到完整路徑並讀取圖片加入圖像數組
中,截取.csv的每個條目分號後位數(ID),加入標籤數組中。
import cv2
import os
import sys
import numpy as np
import csv
def parse_csv(): # 逐行解析csv文件
csv_file = open("./a.csv")
csv_lines = csv.reader(csv_file)
path = []
tot = 0
for line in csv_lines:
path.append(line)
tot += 1
return path
def read_images(root):
path = parse_csv()
X , y = [] , [] # x: 圖像數組 y: 標籤數組
i = 0
tot = len(path)
while i < tot :
pic_path = root + path[i][0][0:-2] #獲取用戶圖片集完整路徑
#print(pic_path)
try:
im = cv2.imread(pic_path, cv2.IMREAD_GRAYSCALE)
if im is not None:
im = cv2.resize(im, (200, 200))
else:
continue
X.append(np.asarray(im, dtype=np.uint8))
id = path[i][0].split(';')[1:]
# print(id)
y.append(id) # ID
except IOError as e:
print("I/O error({0}):{1}".format(e.errno, e.strerror))
except:
print("Unexpected error:", sys.exc_info()[0])
raise
i += 1
return [X,y]
def face_rec():
filepath = 'F:/pyCharm/cv/chapter5/data/at/'
names = ['Dave','Jane','Jack']
[X,y] = read_images(filepath)
y = np.asarray( y , dtype=np.int32 )
model = cv2.face.EigenFaceRecognizer_create() # 基於Eigenfaces的人臉識別
# model = cv2.face.LBPHFaceRecognizer_create() # 基於LBPH的人臉識別
model.train( np.asarray(X) , np.asarray(y) ) # train()中傳入圖像數組,標籤數組(ID)
face_cascade = cv2.CascadeClassifier('F:\pyCharm\cv\chapter5\cascades\haarcascade_frontalface_default.xml')
camera = cv2.VideoCapture(0)
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) 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
camera.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
face_rec()