Face Recognition
人臉辨識順序:
偵測人臉--->臉部裁切-->資料訓練--->人臉辨識
Face Detection with Open CV
訓練模型
import os
import cv2
import numpy as np
# 載入人臉追蹤模型
detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
#創建識別模型,使用LBPHFace演算法識別,Confidence評分低於50是可靠,0是完全契合
model = cv2.face.LBPHFaceRecognizer_create()
#創建識別模型,使用FisherFace演算法識別,Confidence評分低於4000是可靠,0是完全契合
#model = cv2.face.FisherFaceRecognizer_create()
#創建識別模型,使用EigenFace演算法識別,Confidence評分低於4000是可靠,0是完全契合
#model = cv2.face.EigenFaceRecognizer_create()
faces = [] # 儲存人臉位置大小的串列
ids = [] # 記錄該人臉 id 的串列
directory="./dataset/"
face_list=''
for _,subdir,_ in os.walk(directory):
for i in range(len(subdir)):
path=directory + subdir[i] + '/'
face_list+= str(i) + ' ' + subdir[i] +'\n'
for j in os.listdir(path):
filename=path+j
print(filename)
img= cv2.imdecode(np.fromfile(filename,dtype=np.uint8),-1)
#img = cv2.imread(filename) # 依序開啟每一張
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 色彩轉換成黑白
img_np = np.array(gray,'uint8') # 轉換成指定編碼的 numpy 陣列
face = detector.detectMultiScale(gray) # 擷取人臉區域
for(x,y,w,h) in face:
faces.append(img_np[y:y+h,x:x+w]) # 記錄人臉的位置和大小內像素的數值
ids.append(i) # 記錄人臉對應的 id,只能是整數
#將人臉標籤寫成文字檔
path = 'face_label.txt'
f = open(path, 'w')
f.write(face_list)
f.close()
print('training...') # 提示開始訓練
model.train(faces,np.array(ids)) # 開始訓練
model.save('face.yml') # 訓練完成儲存為 face.yml
print('ok!')
人臉辨識
import cv2
import numpy as np
from PIL import Image,ImageDraw,ImageFont
def putchinesetext(frame_img,text,pos,color):
#將opencv陣列格式轉成PIL影像
img=Image.fromarray(cv2.cvtColor(frame_img, cv2.COLOR_BGR2RGB))
myfont=ImageFont.truetype('wt014.ttf',14)
draw=ImageDraw.Draw(img)
draw.text(pos,text,color,font=myfont)
return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
# 啟用訓練人臉模型方法
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('face.yml')
cascade_path = "haarcascade_frontalface_default.xml"
face_cascade = cv2.CascadeClassifier(cascade_path)
cap = cv2.VideoCapture(0)
while True:
ret, img = cap.read()
if not ret:
print("Cannot receive frame")
break
img = cv2.resize(img,(320,240)) # 縮小尺寸,加快辨識效率
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 轉換成黑白
faces = face_cascade.detectMultiScale(gray) # 追蹤人臉 ( 目的在於標記出外框 )
# 建立姓名和 id 的對照表
name={}
f = open('face_label.txt')
for line in f.readlines():
id,sname=line.split()
name[id]=sname
f.close
# 依序判斷每張臉屬於哪個 id
for(x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) # 標記人臉外框
idnum,confidence = recognizer.predict(gray[y:y+h,x:x+w]) # 取出 id 號碼以及信心指數 confidence
if confidence < 80:
# 如果信心指數大於 60,取得對應的名字
text = name[str(idnum)] + str(round(confidence,2))
else:
text = 'Unknow' # 不然名字就是 ???
# 在人臉外框旁加上名字
print(round(confidence,2))
cimg=putchinesetext(img,text,(x,y-20),(0,255,0))
cv2.imshow('oxxostudio', cimg)
if cv2.waitKey(5) == ord('q'):
break # 按下 q 鍵停止
cap.release()
cv2.destroyAllWindows()
Face Detection with FaceNet-Pytorch
檢測照片:
from facenet_pytorch import MTCNN
import torch
import cv2
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
mtcnn=MTCNN(keep_all=True,device=device)
def Picture(window_name,img):
faces,prob_list=mtcnn(img, return_prob=True)
if faces is not None:
boxes,_=mtcnn.detect(img)
print("檢測人臉數目:",len(boxes))
for i,box in enumerate(boxes):
if prob_list[i]>0.9:
x1,y1=int(box.tolist()[0]),int(box.tolist()[1])
x2,y2=int(box.tolist()[2]),int(box.tolist()[3])
cv2.rectangle(img, (x1,y1),(x2,y2), (0, 255, 0), 2)
cv2.putText(img, f"confidence: {str(round(prob_list[i], 3))}", (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 2)
cv2.imwrite(f'{file[:-4]}_output{file[-4:]}',img)
cv2.imshow(window_name, img)
cv2.waitKey(0)
if __name__ == '__main__':
file='demo.jpg'
img=cv2.imread(file)
Picture("Face_Detect",img)
檢測影片
from facenet_pytorch import MTCNN
import torch
import cv2
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
mtcnn=MTCNN(keep_all=True,device=device)
def CatchVideo(window_name):
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if ret==False:
break
faces,prob_list=mtcnn(frame, return_prob=True)
if faces is not None:
boxes,_=mtcnn.detect(frame)
print("檢測人臉數目:",len(boxes))
for i,box in enumerate(boxes):
if prob_list[i]>0.9:
x1,y1=int(box.tolist()[0]),int(box.tolist()[1])
x2,y2=int(box.tolist()[2]),int(box.tolist()[3])
cv2.rectangle(frame, (x1,y1),(x2,y2), (0, 255, 0), 2)
cv2.putText(frame, f"confidence: {str(round(prob_list[i], 3))}", (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 2)
cv2.imshow(window_name, frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
#釋放鏡頭
cap.release()
#關閉視窗
cv2.destroyAllWindows()
if __name__ == '__main__':
CatchVideo("Face_Detect")
Face Recognition with FaceNet-Pytorch
訓練模型
from facenet_pytorch import MTCNN, InceptionResnetV1
import torch
from torch.utils.data import DataLoader
from torchvision import datasets
import os
#如果是Windows系列,wokers=0,否則(posix, java),workers=4
workers = 0 if os.name == 'nt' else 4
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print('Running on device: {}'.format(device))
mtcnn = MTCNN(
image_size=160, margin=0, min_face_size=20,
thresholds=[0.6, 0.7, 0.7], factor=0.709, post_process=True,
device=device
)
resnet = InceptionResnetV1(pretrained='vggface2').eval().to(device)
def collate_fn(x):
return x[0]
dataset = datasets.ImageFolder('./dataset/test_images')
dataset.idx_to_class={i:c for c,i in dataset.class_to_idx.items()}
loader = DataLoader(dataset, collate_fn=collate_fn, num_workers=workers)
#從圖像取出160x160的人臉
aligned = []
#姓名列表
names = []
for x, y in loader:
path=f'./dataset/aligned/{dataset.idx_to_class[y]}/'
if not os.path.exists(path):
i=1
os.mkdir(path)
x_aligned, prob = mtcnn(x, return_prob=True,save_path=path + '{}.jpg'.format(i))
i+=1
if x_aligned is not None:
print(f'Face detected with probability: {prob:8f}')
aligned.append(x_aligned)
names.append(dataset.idx_to_class[y])
aligned = torch.stack(aligned).to(device)
#提取所有人臉的特徵向量,每個向量的長度512
embeddings = resnet(aligned).detach().cpu()
#儲存模型
data=[embeddings,names]
torch.save(data,'nths.pt')
人臉辨識
from facenet_pytorch import MTCNN, InceptionResnetV1
from PIL import Image,ImageDraw,ImageFont
import torch
import cv2
import numpy as np
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
mtcnn=MTCNN(keep_all=True,device=device)
resnet=InceptionResnetV1(pretrained='vggface2').eval().to(device)
load_data=torch.load("nths.pt")
embeddings=load_data[0]
names=load_data[1]
def detect_frame(frame_img):
global who
#將opencv陣列格式轉成PIL影像
img=Image.fromarray(cv2.cvtColor(frame_img, cv2.COLOR_BGR2RGB))
faces,prob_list=mtcnn(img, return_prob=True)
if faces is not None:
boxes,_=mtcnn.detect(img)
draw=ImageDraw.Draw(img)
myfont=ImageFont.truetype('wt014.ttf',14)
print("檢測人臉數目:",len(boxes))
for i,box in enumerate(boxes):
draw.rectangle(box.tolist(),outline=(255,0,0))
face_embedding=resnet(faces[i].unsqueeze(0).to(device))
#將人臉特徵距離儲存到probs陣列中
probs=[(face_embedding - embeddings[i]).norm().item() for i in range(embeddings.size()[0])]
#取得最短距離的索引
index=probs.index(min(probs))
if prob_list[i]>0.99:
name=names[index]
else:
name="Unknow"
draw.text((int(box[0]),int(box[1])),str(name)+str(round(prob_list[i],2)),fill=(255,0,0),font=myfont)
return img
def CatchVideo(window_name):
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if ret==False:
break
myframe=detect_frame(frame)
#將PIL影像轉回opencv陣列格式
cvimg = cv2.cvtColor(np.array(myframe), cv2.COLOR_RGB2BGR)
cv2.imshow(window_name, cvimg)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
#釋放鏡頭
cap.release()
#關閉視窗
cv2.destroyAllWindows()
if __name__ == '__main__':
CatchVideo("Vedio")
Facial Landmark: MTCNN
import time
import cv2
import mtcnn
def CatchVideo(window_name):
detector = mtcnn.MTCNN()
time.sleep(2.0)
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if ret==False:
break
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
faces = detector.detect_faces(rgb)
for face in faces:
(x, y, w, h) = face['box']
keypoints = face['keypoints']
conf = face['confidence']
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(frame, f"confidence: {str(round(conf, 3))}", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 2)
for (s0, s1) in keypoints.values():
cv2.circle(frame, (s0, s1), 2, (0, 0, 255), -1)
cv2.imshow(window_name, frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
#釋放鏡頭
cap.release()
#關閉視窗
cv2.destroyAllWindows()
if __name__ == '__main__':
CatchVideo("Vedio")