人臉識別在現實生活中有很是普遍的應用,例如iPhone X的識別人臉解鎖屏幕、人臉識別考勤機、人臉識別開門禁、刷臉坐高鐵,還有識別人臉虛擬化妝、美顏,甚至支付寶還推出了刷臉支付、建設銀行還實現了刷臉取錢……,可見人臉識別的用處很是廣。
既然人臉識別這麼有用,那咱們可否本身來實現一我的臉識別模型呢?
答案是確定的。python
接下來將在以前咱們搭建好的AI基礎環境上(見文章:搭建AI基礎環境),實現人臉識別模型。git
0、人臉識別主要流程
要識別一張人臉,通常須要通過如下步驟:(1)經過攝像頭或上傳圖片等方式採集圖像;(2)檢測圖像裏面有沒有人臉,若是有就把人臉所在的區域圈出來;(3)對人臉圖像進行灰度處理、噪聲過濾等預處理;(4)提取人臉的特徵數據出來;(5)將提取的人臉特徵數據與人臉庫進行匹配,輸出識別結果。主要流程以下圖所示:
下面將按步驟逐個介紹實現方式。github
一、圖像採集
本文采用OpenCV採集圖像。
OpenCV是處理圖像的流行工具,具有多種圖像處理的能力,可跨平臺運行在Linux、Windows、Mac OS等多個平臺,使用C++編寫,提供Python、C++、Ruby等語言的接口。在Python環境中,OpenCV和Tensorflow能很好地相互配合,利用OpenCV可方便快速地採集、處理圖像,配合Tensorflow能很好地實現圖像的建模工做。
(1)安裝OpenCV
在conda虛擬環境中,OpenCV的安裝方式以下:算法
conda install --channel https://conda.anaconda.org/menpo opencv3
(2)採集圖像
在OpenCV中調用攝像頭採集圖像的方式以下:數據庫
# 一、調用攝像頭進行拍照 cap = cv2.VideoCapture(0) ret, img = cap.read() cap.release()
若是已是有現成的圖片,則在OpenCV中直接讀取就能夠:bash
# 二、根據提供的路徑讀取圖像 img=cv2.imread(img_path)
二、人臉檢測
人臉檢測的主要目的是檢測採集的圖像中有沒有人臉,並肯定出人臉所在的位置和大小。檢測人臉有不少種方式,下面介紹幾種經常使用的方法:
(1)使用OpenCV檢測人臉
OpenCV中自帶了人臉檢測器,基於Haar算法進行人臉檢測。Haar算法的基本思路是這樣的,經過使用一些矩形模板對圖像進行掃描,例以下圖中的兩個矩形模板,中間一幅在掃描到眼睛時發現眼睛區域的顏色比周邊臉頰區域的顏色深,表示符合眼睛的特徵;右邊一幅在掃描到鼻樑時發現鼻樑兩側比鼻樑的顏色要深,符合鼻樑的特徵。一樣地,再經過其它的矩形模板進行掃描,當發現具有眼睛、鼻樑、嘴巴等特徵且超過必定的閾值時,則斷定爲是一張人臉。
使用OpenCV檢測人臉,要先加載人臉分類器網絡
代碼以下:app
# 一、使用 opencv 檢測人臉 # 加載人臉檢測分類器(正面人臉),位於OpenCV的安裝目錄下 face_cascade=cv2.CascadeClassifier('/data/anaconda3/envs/tensorflow/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml') # 轉灰度圖 img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 檢測人臉(可能有多張),返回人臉位置信息(x,y,w,h) img_faces=face_cascade.detectMultiScale(img_gray)
(2)使用Dlib檢測人臉
Dlib是一個包含機器學習算法開源工具包,基於C++編寫,一樣也提供了Python語言接口。使用Dlib也能很方便地檢測出人臉,檢測的效果要比OpenCV好,安裝方式以下:機器學習
# 安裝 Dlib # 激活 conda 虛擬環境 conda activate tensorflow # 安裝 Dlib conda install -c menpo dlib
代碼以下:分佈式
# Dlib 人臉檢測 detector = dlib.get_frontal_face_detector() dets = detector(img, 1) # 獲取人臉所在的位置 img_faces=[] for i in range(len(dets)): x = dlib.rectangle.left(dets[i]) y = dlib.rectangle.top(dets[i]) h = dlib.rectangle.height(dets[i]) w = dlib.rectangle.width(dets[i]) img_faces.append([x,y,w,h])
(3)使用face_recognition檢測人臉
face_recognition是基於dlib的深度學習人臉識別庫,在戶外臉部檢測數據庫基準(Labeled Faces in the Wild benchmark,簡稱LFW)上的準確率達到了99.38%。
使用face_recognition檢測人臉,安裝方式以下:
# 安裝 face_recognition # 須要先安裝dlib , 還有 CMake ( sudo apt-get install cmake ) # 激活 conda 虛擬環境 conda activate tensorflow # 因爲 face_recognition 在 conda 中沒有相應的軟件包,所以經過 pip 安裝 pip install face_recognition
代碼以下:
# 檢測人臉 face_locations = face_recognition.face_locations(img) # 獲取人臉的位置信息 img_faces = [] for i in range(len(face_locations)): x = face_locations[i][3] y = face_locations[i][0] h = face_locations[i][2] - face_locations[i][0] w = face_locations[i][1] - face_locations[i][3] img_faces.append([x, y, w, h])
(4)使用FaceNet檢測人臉
FaceNet是谷歌發佈的人臉檢測算法,發表於CVPR 2015,這是基於深度學習的人臉檢測算法,利用相同人臉在不一樣角度、姿態的高內聚性,不一樣人臉的低耦合性,使用卷積神經網絡所訓練出來的人臉檢測模型,在LFW人臉圖像數據集上準確度達到99.63%,比傳統方法的準確度提高了將近30%,效果很是好。
使用FaceNet檢測人臉,安裝方式以下:
a. 到FaceNet的github上將源代碼和相應的模型下載下來(https://github.com/davidsandberg/facenet)
b. 將要用到的python文件導入到本地的 facenet 庫中,以下圖所示:
代碼以下:
with tf.Graph().as_default(): sess = tf.Session() with sess.as_default(): pnet, rnet, onet = facenet.detect_face_fromfacenet.create_mtcnn(sess, './facenet/model_check_point/') minsize = 20 threshold = [0.6, 0.7, 0.7] factor = 0.709 bounding_boxes, _ = facenet.detect_face_fromfacenet.detect_face(img, minsize, pnet, rnet, onet, threshold, factor) img_faces = [] for face_position in bounding_boxes: face_position = face_position.astype(int) x = face_position[0] y = face_position[1] h = face_position[3] - face_position[1] w = face_position[2] - face_position[0] img_faces.append([x, y, w, h])
三、預處理
在作完圖像的人臉檢測後,獲得了人臉所在的位置和大小,但因爲受到各類條件的限制和隨機干擾,須要根據實際採集的圖像質量狀況進行預處理,以提高圖像的質量。主要的預處理有:
(1)調整尺寸:根據網絡傳輸帶寬、電腦處理性能等相關的要求,對檢測的人臉圖像進行尺寸調整;
(2)直方圖均衡化:根據實際狀況,對圖像做直方圖均衡,避免因光線問題,致使人臉上出現明顯陰影的狀況,從而影響了識別的準確率;
(3)噪聲過濾:經過使用中值濾波器、高斯濾波器等對圖像進行噪聲過濾,以提高圖像質量;
(4)銳化:因爲攝像頭對焦的問題,致使某些採集的照片出現模糊,經過銳化操做,提高圖像的清晰度;
(5)光線補償:對於一些光線不足的圖像進行光線補償,提高照片的亮度,便於後續更加準確地提取特徵。
四、特徵提取
人臉是由眼睛、鼻子、嘴、下巴等局部構成,這些局部之間的結構關係,即是做爲人臉的重要特徵。人臉特徵的提取,是對人臉進行特徵建模的過程。
下面介紹提取人臉特徵的幾種方法:
(1)使用Dlib提取人臉特徵(68維)
使用Dlib可提取人臉的68個特徵點,這些特徵點描述了眉毛、眼睛、鼻子、嘴巴,以及整個臉部的輪廓,以下圖所示:
使用Dlib提取人臉特徵的代碼以下:
# 一、dlib 提取人臉特徵 # opencv 沒法直接提取人臉特徵,在這裏設置 opencv 也採用 dlib 的特徵提取方式 # 下載模型:http://dlib.net/files/ # 下載文件:shape_predictor_68_face_landmarks.dat.bz2 # 解壓文件,獲得 shape_predictor_68_face_landmarks.dat 文件 # 獲取人臉檢測器 predictor = dlib.shape_predictor('./dlib_model/shape_predictor_68_face_landmarks.dat') for index,face in enumerate(dets): face_feature = predictor(face_img,face)
(2)使用face_recognition提取人臉特徵(128維)
face_recognition提取的人臉特徵比Dlib更加細緻,達到128個點,一樣也是描述了眉毛、眼睛、鼻子、嘴巴等局部的關係。
使用face_recognition提取人臉特徵的代碼以下:
# 二、face_recognition 提取人臉特徵 face_feature = face_recognition.face_encodings(face_img)
(3)使用FaceNet提取人臉特徵(128維)
使用FaceNet提取的人臉特徵一樣也有128維,代碼以下:
with tf.Graph().as_default(): sess = tf.Session() with sess.as_default(): batch_size=None image_size=160 images_placeholder = tf.placeholder(tf.float32, shape=(batch_size,image_size,image_size, 3), name='input') phase_train_placeholder = tf.placeholder(tf.bool, name='phase_train') model_checkpoint_path = './facenet/model_check_point/' input_map = {'input': images_placeholder, 'phase_train': phase_train_placeholder} model_exp = os.path.expanduser(model_checkpoint_path) meta_file, ckpt_file = get_model_filenames(model_exp) saver = tf.train.import_meta_graph(os.path.join(model_exp, meta_file), input_map=input_map) saver.restore(sess, os.path.join(model_exp, ckpt_file)) face_img = cv2.resize(face_img, (image_size, image_size), interpolation=cv2.INTER_CUBIC) data = np.stack([face_img]) embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0") feed_dict = {images_placeholder: data, phase_train_placeholder: False} face_feature = sess.run(embeddings, feed_dict=feed_dict)
五、匹配識別
在提取好人臉特徵後,即是要用於識別這我的是誰。
將提取的人臉特徵與數據庫中存儲的人臉特徵數據進行檢索匹配,當匹配的類似度超過必定的閾值後,便將匹配結果輸出。
通常經常使用如下方式進行匹配:
(1)基於距離判斷(歐氏距離)
將提取出來的人臉特徵(68維或128維),逐個與數據庫中的人臉特徵計算距離,通常使用歐氏距離,而後取最小的距離,當超過閾值時便輸出識別結果。
這種方式簡單易用,但卻常常會誤判,這是因爲人的表情很豐富,數據庫中並不必定會把全部表情都存儲起來。
基於歐氏距離的人臉識別代碼以下:
# 一、歐氏距離 min_dis=99999 min_idx=-1 for i in range(len(features)): dis=np.sqrt(np.sum(np.square(face_feature-features[i]))) if dis<min_dis: min_dis=dis min_idx=i name=labels[min_idx]
(2)基於分類算法(KNN)
人臉特徵的匹配本質上也是一個分類過程,即將屬於同一我的的分類出來。採用K近鄰(KNN)算法進行分類,這是數據挖掘中最簡單的方法之一。所謂K近鄰,就是K個最近鄰居,就是說每一個樣本均可以用它最接近的K個鄰居來表明。所以,KNN算法的核心思想是若是一個樣本的K個最相鄰的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別。
基於KNN的人臉識別代碼以下:
# 二、KNN knn = neighbors.KNeighborsClassifier(n_neighbors=2) knn.fit(features, labels) name = knn.predict([face_feature]) name = name[0]
經過以上步驟,咱們瞭解了幾種常見的人臉檢測、識別算法,並掌握了一個完整的人臉識別程序的編寫過程。
關注本人公衆號「大數據與人工智能Lab」(BigdataAILab),而後回覆「代碼」關鍵字可獲取 完整源代碼。
推薦相關閱讀