用Python檢測人臉特徵

做者|Juan Cruz Martinez
編譯|Flin
來源|towardsdatasciencejava

今天,咱們將學習如何檢測圖像中的人臉並提取面部特徵,如眼睛、鼻子、嘴巴等。咱們能夠將這些信息做爲一個預處理步驟來完成,例如捕捉照片中人物的人臉(手動或經過機器學習),建立效果來「加強」咱們的圖像(相似於Snapchat等應用程序中的效果),對人臉進行情感分析等等。python

過去,咱們已經討論過如何使用OpenCV來檢測圖像中的形狀,可是今天咱們將經過引入DLib和從圖像中提取面部特徵來將其提高到一個新的水平。算法

  • 相關閱讀:

https://towardsdatascience.co...shell

Dlib是一個高級的機器學習庫,它是爲解決複雜的現實世界問題而建立的。這個庫是用C++編程語言建立的,它與C/C++、Python和java一塊兒工做。編程

值得注意的是,本教程可能須要對OpenCV庫有必定的瞭解,例如如何處理圖像、打開相機、圖像處理和一些小技巧。windows

它是如何工做的?

咱們的臉有幾個能夠識別的特徵,好比眼睛、嘴巴、鼻子等等。當咱們使用DLib算法檢測這些特徵時,咱們實際上獲得了每一個特徵的點的映射。
該映射由67個點(稱爲地標點)組成,可識別如下特徵:網絡

  • 顎點= 0–16
  • 右眉點= 17–21
  • 左眉點= 22–26
  • 鼻點= 27–35
  • 右眼點= 36–41
  • 左眼點= 42–47
  • 口角= 48–60
  • 嘴脣分數= 61–67

如今讓咱們來了解如何提取特徵。機器學習

安裝要求

與往常同樣,本文將用代碼演示示例,並將逐步指導你實現一個完整的人臉特徵識別示例。可是在開始以前,你須要啓動一個新的Python項目並安裝3個不一樣的庫:編程語言

  • opencv python
  • dlib

若是像我同樣使用pipenv,可使用如下命令安裝全部這些文件:ide

pipenv install opencv-python, dlib

若是你使用的是Mac和某些版本的Linux,則在安裝dlib時可能會遇到一些問題,若是在安裝過程當中遇到編譯錯誤,請確保檢查使用的CMake庫版本。在Mac中,確保你有可用的CMake,而且可使用正確的版本運行:

brew install cmake

對於其餘操做系統,請在線檢查以得到特定支持。

步驟1:載入並顯示圖片

咱們將從小處着手並以代碼爲基礎,直到有一個能夠正常工做的示例爲止。

一般,我喜歡使用繪圖來渲染圖像,可是因爲咱們在稍後的文章中準備了一些很酷的東西,所以咱們將作一些不一樣的事情,而且將建立一個窗口來展現咱們的工做結果。

讓咱們一塊兒看看代碼吧!

import cv2
# read the image
img = cv2.imread("face.jpg")
# show the image
cv2.imshow(winname="Face", mat=img)
# Wait for a key press to exit
cv2.waitKey(delay=0)
# Close all windows
cv2.destroyAllWindows()

很簡單,對吧?咱們只是用imread加載圖像,而後告訴OpenCV在winname中顯示圖像,這將打開窗口並給它一個標題。

以後,咱們須要暫停執行,由於當腳本中止時,窗口會被破壞,因此咱們使用cv2.waitKey來保持窗口,直到按下某個鍵,而後銷燬窗口並退出腳本。

若是使用代碼並在代碼目錄中添加了一個名爲face.jpg的圖像,你應該獲得以下內容:

原始圖像:

步驟2:人臉識別

到目前爲止,咱們尚未對圖像作任何處理,只是把它呈如今一個窗口中,很是無聊,可是如今咱們將開始編碼好的內容,咱們將從識別圖像中哪裏有一張臉開始。

爲此,咱們將使用名爲get_frontial_face_detector()的Dlib函數,很是直觀。可是有一個警告,這個函數只適用於灰度圖像,因此咱們必須首先使用OpenCV。

get_frontial_face_detector()將返回一個檢測器,該檢測器是一個咱們能夠用來檢索人臉信息的函數。每一個面都是一個對象,其中包含能夠找到圖像的點。

但咱們最好在代碼上看看:

import cv2
import dlib
# Load the detector
detector = dlib.get_frontal_face_detector()
# read the image
img = cv2.imread("face.jpg")
# Convert image into grayscale
gray = cv2.cvtColor(src=img, code=cv2.COLOR_BGR2GRAY)
# Use detector to find landmarks
faces = detector(gray)
for face in faces:
    x1 = face.left() # left point
    y1 = face.top() # top point
    x2 = face.right() # right point
    y2 = face.bottom() # bottom point
    # Draw a rectangle
    cv2.rectangle(img=img, pt1=(x1, y1), pt2=(x2, y2), color=(0, 255, 0), thickness=4)
# show the image
cv2.imshow(winname="Face", mat=img)
# Wait for a key press to exit
cv2.waitKey(delay=0)
# Close all windows
cv2.destroyAllWindows()

上面的代碼將從圖像中檢索全部面部,並在每一個面部上渲染一個矩形,從而產生以下圖像:

到目前爲止,咱們在發現人臉方面作得很好,可是咱們仍然須要一些工做來提取全部特徵(地標)。接下來讓咱們開始吧。

步驟3:識別人臉特徵

你喜歡魔術嗎?到目前爲止,DLib的工做方式至關神奇,只需幾行代碼咱們就能夠實現不少,而如今咱們遇到了一個全新的問題,它還會繼續這麼簡單嗎?

回答是確定的!原來DLib提供了一個名爲shape_predictor()的函數,它將爲咱們提供全部的魔法,可是須要一個預先訓練的模型才能工做。

有幾種模型能夠與shape_predictor一塊兒工做,我正在使用的模型能夠在這裏下載,也能夠嘗試其餘模型。

讓咱們看看新代碼如今是什麼樣子

import cv2
import dlib
# Load the detector
detector = dlib.get_frontal_face_detector()
# Load the predictor
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
# read the image
img = cv2.imread("face.jpg")
# Convert image into grayscale
gray = cv2.cvtColor(src=img, code=cv2.COLOR_BGR2GRAY)
# Use detector to find landmarks
faces = detector(gray)
for face in faces:
    x1 = face.left() # left point
    y1 = face.top() # top point
    x2 = face.right() # right point
    y2 = face.bottom() # bottom point
    # Look for the landmarks
    landmarks = predictor(image=gray, box=face)
    x = landmarks.part(27).x
    y = landmarks.part(27).y
    # Draw a circle
    cv2.circle(img=img, center=(x, y), radius=5, color=(0, 255, 0), thickness=-1)
# show the image
cv2.imshow(winname="Face", mat=img)
# Wait for a key press to exit
cv2.waitKey(delay=0)
# Close all windows
cv2.destroyAllWindows()

像之前同樣,咱們老是在同一個代碼上構建代碼,如今使用咱們的預測函數爲每一個人臉找到地標。如今我還在作一些奇怪的事情,好比27號在那裏作什麼?

landmarks = predictor(image=gray, box=face)
x = landmarks.part(27).x
y = landmarks.part(27).y

咱們的預測函數將返回一個包含全部68個點的對象,根據咱們以前看到的圖片,若是你注意到的話,會發現點27正好在眼睛之間,因此若是全部的計算正確,你應該看到一個綠點在眼睛之間,以下圖所示:

咱們已經很接近了,如今讓咱們渲染全部的點,而不是隻渲染一個:

import cv2
import numpy as np
import dlib
# Load the detector
detector = dlib.get_frontal_face_detector()
# Load the predictor
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
# read the image
img = cv2.imread("face.jpg")
# Convert image into grayscale
gray = cv2.cvtColor(src=img, code=cv2.COLOR_BGR2GRAY)
# Use detector to find landmarks
faces = detector(gray)
for face in faces:
    x1 = face.left() # left point
    y1 = face.top() # top point
    x2 = face.right() # right point
    y2 = face.bottom() # bottom point
    # Create landmark object
    landmarks = predictor(image=gray, box=face)
    # Loop through all the points
    for n in range(0, 68):
        x = landmarks.part(n).x
        y = landmarks.part(n).y
        # Draw a circle
        cv2.circle(img=img, center=(x, y), radius=3, color=(0, 255, 0), thickness=-1)
# show the image
cv2.imshow(winname="Face", mat=img)
# Delay between every fram
cv2.waitKey(delay=0)
# Close all windows
cv2.destroyAllWindows()

可是若是你對全部的點都不感興趣呢?實際上,你能夠調整你的範圍間隔來得到上面術語表中指定的任何特徵,就像我在這裏作的那樣:

太棒了,但咱們能作點更酷的事嗎?

步驟4:實時檢測

是的,你沒看錯!這可能就是你想要的效果!下一步是鏈接咱們的網絡攝像頭,從你的視頻流中進行實時地標識別。

你能夠經過使用相機遍歷視頻幀或使用視頻文件來對面部進行實時面部地標檢測。

若是要使用本身的攝像機,請參考如下代碼,若是使用的是視頻文件,請確保將數字0更改成視頻路徑。

若是要結束窗口,請按鍵盤上的ESC鍵:

import cv2
import dlib

# Load the detector
detector = dlib.get_frontal_face_detector()

# Load the predictor
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

# read the image
cap = cv2.VideoCapture(0)

while True:
    _, frame = cap.read()
    # Convert image into grayscale
    gray = cv2.cvtColor(src=frame, code=cv2.COLOR_BGR2GRAY)

    # Use detector to find landmarks
    faces = detector(gray)

    for face in faces:
        x1 = face.left()  # left point
        y1 = face.top()  # top point
        x2 = face.right()  # right point
        y2 = face.bottom()  # bottom point

        # Create landmark object
        landmarks = predictor(image=gray, box=face)

        # Loop through all the points
        for n in range(0, 68):
            x = landmarks.part(n).x
            y = landmarks.part(n).y

            # Draw a circle
            cv2.circle(img=frame, center=(x, y), radius=3, color=(0, 255, 0), thickness=-1)

    # show the image
    cv2.imshow(winname="Face", mat=frame)

    # Exit when escape is pressed
    if cv2.waitKey(delay=1) == 27:
        break

# When everything done, release the video capture and video write objects
cap.release()

# Close all windows
cv2.destroyAllWindows()

最後的結果是:

在弱光條件下,儘管上面的圖像中有一些錯誤,但其結果也至關準確,若是照明效果好的話結果會更加準確。

結論

OpenCV和DLib是兩個功能很是強大的庫,它們簡化了ML和計算機視覺的工做,今天咱們只是觸及了最基本的東西,還有不少東西須要從中學習。

很是感謝你的閱讀!

原文連接:https://towardsdatascience.co...

歡迎關注磐創AI博客站:
http://panchuang.net/

sklearn機器學習中文官方文檔:
http://sklearn123.com/

歡迎關注磐創博客資源彙總站:
http://docs.panchuang.net/

相關文章
相關標籤/搜索