三分鐘帶你入門人臉識別
人臉識別是AI研究帶給世界的眾多奇跡之一。對于許多技術(shù)人員來說,這是一個充滿好奇的話題-他們希望對事物的工作方式有基本的了解。讓我們潛入主題,看看事情如何運作。
人臉識別
解決此類問題時,最好不要重新發(fā)明輪子-我們不能!最好遵循研究人員提供給我們的模型。開源中也有很多可用的工具。這樣的Python庫之一是face_recognition。它可以通過幾個步驟工作:
- 識別給定圖像中的人臉
- 識別面部特征
- 生成128個值的人臉編碼向量
基于這種編碼,我們可以測量兩個臉部圖像之間的相似度-可以告訴我們它們是否屬于同一個人。
首先安裝face_recognition模塊
- pip install face_recognition
導入模塊
接下來,我們導入所需的模塊
- import PIL.Image
- import PIL.ImageDraw
- import requests
- from io import BytesIO
- from IPython.display import display
- import face_recognition
載入圖片
接下來,我們加載圖片。我已將圖像存儲在我的Github帳戶中。這樣我們就可以從URL中讀取原始圖像。
- response = requests.get("https://raw.githubusercontent.com/solegaonkar/solegaonkar.github.io/master/img/rahul1.jpeg")
- fr_image = face_recognition.load_image_file(BytesIO(response.content))
識別面孔
加載面部后,讓我們看一下face_recognition模塊的各個部分。它如何識別人臉?
- face_locations = face_recognition.face_locations(fr_image)
- number_of_faces = len(face_locations)
- print("I found {} face(s) in this photograph.".format(number_of_faces))
這給了我們一個輸出:
- I found 1 face(s) **in** this photograph.</span>
這意味著,該算法僅在圖像中找到了一張臉。讓我們看看所識別的圖像和面部。
- pil_image = PIL.Image.fromarray(fr_image)
- for face_location in face_locations:
- # Print the location of each face in this image. Each face is a list of co-ordinates in (top, right, bottom, left) order.
- top, right, bottom, left = face_location
- print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
- # Let's draw a box around the face
- draw = PIL.ImageDraw.Draw(pil_image)
- draw.rectangle([left, top, right, bottom], outline="black")
這給了我們一個輸出
- A face **is** located at pixel location Top: 68, Left: 117, Bottom: 291, Right: 340</span>
上面的代碼還修改了圖像以在臉部周圍繪制一個矩形。讓我們檢查一下是否運作良好。
已經(jīng)可以了。
人臉編碼
這是我們的面孔。但是,對于我們的算法而言,它只是RGB值的數(shù)組—匹配從我們提供給它的數(shù)據(jù)樣本中學到的模式。
對于面部識別,該算法記錄了面部的某些重要測量值,例如眼睛的顏色和大小和傾斜度,眉毛之間的間隙等。所有這些共同定義了面部編碼-從圖像中獲取的信息-即用于識別特定面孔。
為了了解從面部讀取的內(nèi)容,讓我們看一下讀取的編碼。
- face_encodings = face_recognition.face_encodings(fr_image)
- face_encodings[0]
打印出一個巨大的數(shù)組:
- array([-0.10213576, 0.05088161, -0.03425048, -0.09622347, -0.12966095,
- 0.04867411, -0.00511892, -0.03418527, 0.2254715 , -0.07892745,
- 0.21497472, -0.0245543 , -0.2127848 , -0.08542262, -0.00298059,
- 0.13224372, -0.21870363, -0.09271716, -0.03727289, -0.1250658 ,
- 0.09436664, 0.03037129, -0.02634972, 0.02594662, -0.1627259 ,
- -0.29416466, -0.12254384, -0.15237436, 0.14907973, -0.09940194,
- 0.02000656, 0.04662619, -0.1266906 , -0.11484023, 0.04613583,
- 0.1228286 , -0.03202137, -0.0715076 , 0.18478717, -0.01387333,
- -0.11409076, 0.07516225, 0.08549548, 0.31538364, 0.1297821 ,
- 0.04055009, 0.0346106 , -0.04874525, 0.17533901, -0.22634712,
- 0.14879328, 0.09331974, 0.17943285, 0.02707857, 0.22914577,
- -0.20668915, 0.03964197, 0.17524502, -0.20210043, 0.07155308,
- 0.04467429, 0.02973968, 0.00257265, -0.00049853, 0.18866715,
- 0.08767469, -0.06483966, -0.13107982, 0.21610288, -0.04506358,
- -0.02243116, 0.05963502, -0.14988004, -0.11296406, -0.30011353,
- 0.07316103, 0.38660526, 0.07268623, -0.14636359, 0.08436179,
- 0.01005938, -0.00661338, 0.09306039, 0.03271955, -0.11528577,
- -0.0524189 , -0.11697718, 0.07356471, 0.10350288, -0.03610475,
- 0.00390615, 0.17884226, 0.04291092, -0.02914601, 0.06112404,
- 0.05315027, -0.14561613, -0.01887275, -0.13125736, -0.0362937 ,
- 0.16490118, -0.09027836, -0.00981111, 0.1363602 , -0.23134531,
- 0.0788044 , -0.00604869, -0.05569676, -0.07010217, -0.0408107 ,
- -0.10358225, 0.08519378, 0.16833456, -0.30366772, 0.17561394,
- 0.14421709, -0.05016343, 0.13464174, 0.0646335 , -0.0262765 ,
- 0.02722404, -0.06028951, -0.19448066, -0.07304715, 0.0204969 ,
- -0.03045784, -0.02818791, 0.06679841])
這些數(shù)字中的每一個代表面部編碼的正交分量。
相似
現(xiàn)在讓我們研究下一步-確定面孔之間的相似性。為此,我們需要加載更多圖像。
讓我們首先加載三個圖像。加載圖像時,我們還先找到人臉,再找到人臉編碼。
- response = requests.get("https://raw.githubusercontent.com/solegaonkar/solegaonkar.github.io/master/img/rahul1.jpeg")
- image_of_person_1 = face_recognition.load_image_file(BytesIO(response.content))
- face_locations = face_recognition.face_locations(image_of_person_1)
- person_1_face_encoding = face_recognition.face_encodings(image_of_person_1, known_face_locations=face_locations)
- response = requests.get("https://raw.githubusercontent.com/solegaonkar/solegaonkar.github.io/master/img/rahul2.jpg")
- image_of_person_2 = face_recognition.load_image_file(BytesIO(response.content))
- face_locations = face_recognition.face_locations(image_of_person_2)
- person_2_face_encoding = face_recognition.face_encodings(image_of_person_2, known_face_locations=face_locations)
- response = requests.get("https://raw.githubusercontent.com/solegaonkar/solegaonkar.github.io/master/img/trump.jpg")
- image_of_person_3 = face_recognition.load_image_file(BytesIO(response.content))
- face_locations = face_recognition.face_locations(image_of_person_3)
- person_3_face_encoding = face_recognition.face_encodings(image_of_person_3, known_face_locations=face_locations)
現(xiàn)在,識別相似性并不困難。face_recognition模塊提供了一個簡單的API。
- face_recognition.compare_faces([person_1_face_encoding,person_3_face_encoding], person_2_face_encoding[0], tolerance=0.08)
該方法檢查要比較的兩個面的每個分量,并告訴我們當前分量是否在公差范圍內(nèi)變化。上面的命令顯示如下輸出:
- [array([ True, True, True, True, True, True, True, True, True,
- True, True, True, True, True, True, True, True, True,
- True, True, True, True, True, True, True, True, True,
- True, True, True, True, True, True, True, True, True,
- True, True, True, True, False, True, True, True, True,
- True, True, True, True, True, True, True, True, False,
- True, True, True, True, True, True, True, True, True,
- True, True, True, True, True, False, True, True, True,
- True, True, True, True, True, True, True, True, False,
- True, True, True, True, True, True, True, True, True,
- True, True, True, False, True, True, True, True, True,
- True, True, True, True, True, True, True, True, True,
- True, True, True, True, True, True, True, True, True,
- True, True, True, True, True, True, True, True, False,
- True, True]),
- array([ True, True, True, True, True, True, False, False, False,
- True, True, True, False, True, True, True, False, True,
- False, True, True, True, True, False, True, True, True,
- False, True, True, True, False, True, True, True, True,
- True, True, True, True, False, True, False, True, True,
- True, True, True, False, True, False, True, True, True,
- False, False, True, True, True, True, True, False, True,
- False, False, False, False, True, False, True, False, True,
- False, True, True, True, True, False, True, True, True,
- True, True, True, False, True, True, True, False, True,
- True, False, True, True, True, True, True, True, True,
- True, True, True, True, True, False, False, True, True,
- False, False, False, True, True, False, True, True, True,
- True, True, True, True, True, True, False, False, True,
- True, True])]
這兩個數(shù)組表示給定圖像(在第二個參數(shù)中)與提供的列表(在第一個參數(shù)中)中每個已知面部編碼的相似性。
我們可以看到第一個數(shù)組顯示出更多相似性。可以正確識別該人。
數(shù)碼化妝
如果您喜歡有趣,我們可以使用面部識別庫做更多的事情。我們有一個API,可以幫助我們識別面部的各個特征。
- face_landmarks_list = face_recognition.face_landmarks(fr_image)
- print(face_landmarks_list)
這為我們提供了每個單獨特征曲線的長長列表。
- [{
- 'chin': [(46, 47), (45, 54), (44, 62), (44, 69), (44, 77), (46, 84), (49, 91), (54, 95), (61, 97), (68, 97), (76, 95), (84, 91), (90, 87), (94, 81), (97, 75), (99, 68), (101, 60)],
- 'left_eyebrow': [(51, 42), (54, 39), (58, 39), (63, 40), (67, 42)],
- 'right_eyebrow': [(75, 44), (80, 44), (86, 44), (90, 47), (93, 51)],
- 'nose_bridge': [(70, 48), (68, 52), (67, 56), (66, 60)],
- 'nose_tip': [(60, 64), (62, 65), (65, 67), (68, 66), (71, 66)],
- 'left_eye': [(55, 47), (57, 45), (61, 46), (63, 48), (60, 48), (57, 48)],
- 'right_eye': [(77, 51), (80, 50), (84, 51), (86, 54), (83, 54), (79, 53)],
- 'top_lip': [(54, 75), (58, 72), (61, 72), (64, 73), (66, 73), (70, 75), (73, 80), (71, 79), (66, 75), (63, 75), (61, 74), (56, 75)],
- 'bottom_lip': [(73, 80), (68, 81), (64, 81), (62, 80), (60, 80), (57, 78), (54, 75), (56, 75), (60, 77), (63, 78), (65, 78), (71, 79)]
- }]
我們可以對此圖像應用數(shù)字化妝。
- for face_landmarks in face_landmarks_list:
- pil_image = PIL.Image.fromarray(fr_image)
- d = PIL.ImageDraw.Draw(pil_image, 'RGBA')
- # Make the eyebrows into a nightmare
- d.line(face_landmarks['left_eyebrow'], fill=(0, 0, 0, 255), width=3)
- d.line(face_landmarks['right_eyebrow'], fill=(0, 0, 0, 255), width=3)
- d.polygon(face_landmarks['left_eyebrow'], fill=(0, 0, 0, 255))
- d.polygon(face_landmarks['right_eyebrow'], fill=(0, 0, 0, 255))
- # Gloss the lips
- d.line(face_landmarks['top_lip'], fill=(0, 0, 0, 255), width=10)
- d.line(face_landmarks['bottom_lip'], fill=(0, 0, 0, 255), width=10)
- d.polygon(face_landmarks['bottom_lip'], fill=(255, 0, 0, 255))
- d.polygon(face_landmarks['top_lip'], fill=(255, 0, 0, 255))
- d.line(face_landmarks['top_lip'], fill=(0, 0, 0, 255), width=2)
- d.line(face_landmarks['bottom_lip'], fill=(0, 0, 0, 255), width=2)
- # Chin
- d.polygon(face_landmarks['chin'], fill=(255, 0, 0, 16))
- # Apply some eyeliner
- d.line(face_landmarks['left_eye'] + [face_landmarks['left_eye'][0]], fill=(10, 0, 0, 255), width=6)
- d.line(face_landmarks['right_eye'] + [face_landmarks['right_eye'][0]], fill=(10, 0, 0, 255), width=6)
- # Sparkle the eyes
- d.polygon(face_landmarks['left_eye'], fill=(255, 0, 0, 200))
- d.polygon(face_landmarks['right_eye'], fill=(255, 0, 0, 200))
- display(pil_image)
下面是我們得到的。