【學習筆記】人臉識別系統(1) —— OpenCV人臉檢測


OpenCV是一個開源的跨平臺計算機視覺庫

學習目標是:

  • 學會使用 OpenCV中一系列的圖像操作(採集圖片、讀取圖片、展示圖片以及保存圖片);
  • 理解色彩空間,並使用 OpenCV進行色彩空間轉換;
  • 理解 Harr分類器原理,使用 OpenCV中的 Harr分類器進行人臉檢測。

OpenCV是一個開源的跨平臺計算機視覺庫。跨平臺是指,它可以運行在Linux、Windows、Android和Mac OS等操作系統上。它實現了圖像處理和計算機視覺方面的很多通用算法,具有輕量高效的特點。OpenCV提供了多種語言的編程接口,例如C、C++、Python。


完整的人臉識別流程,一般有如下五個步驟:

  1. 圖像採集:使用攝像機或攝像頭採集含有人臉的圖像或視頻流;
  2. 人臉檢測:檢測圖片中是否包含人臉;
  3. 預處理:對人臉圖像進行灰度處理、噪聲過濾等預處理;
  4. 特徵點提取:提取人臉圖片中包含的特徵數據;
  5. 人臉識別:將新的人臉照片與人臉庫進行算法匹配,輸出識別結果。

圖片基本操作

1.(攝像頭)採集圖片

原始的圖片多數 採用各種攝像頭採集 ,再整理爲圖片數據集。
如果使用OpenCV採集,可以通過cv2.VideoCapture()獲取攝像頭並捕捉畫面中的圖片。函數聲明爲:

cv2.VideoCapture(攝像頭來源)
  • 其中,傳入的參數,指定0時爲默認計算機默認攝像頭,指定1可以更換來源。

然後,獲取捕獲圖像,函數爲:

cap.read()
  • cap.read()返回一個布爾值(True/False)和一幀圖像。

最後釋放捕獲對象,函數爲:

cap.release()

示例如下:

# 引入OpenCV庫
import cv2

# 調用攝像頭進行拍照
cap = cv2.VideoCapture(0)

# 獲取一幀圖片
# 如果捕獲成功,代碼中ret值爲真,img爲捕獲的圖像。
ret, img = cap.read()

# 釋放捕獲對象
cap.release()

2.讀取(已採集)圖片

通常我們 使用採集完成的圖片。在OpenCV中,使用cv2.imread()從文件中加載一張圖片。
函數聲明爲:

cv2.imread(圖片路徑, 標記)
  • 第一個參數爲圖片路徑,圖片應該在當前的工作路徑,或在指定的絕對路徑下。

  • 第二個參數指定圖片被讀取的方式:
    cv2.IMREAD_COLOR : 讀入彩色圖像,默認模式;
    cv2.IMREAD_GRAYSCALE : 以灰度模式讀入圖像;
    cv2.IMREAD_UNCHANGED : 加載圖像包含alpha通道。(alpha通道:控制透明度)

  • 也可以,使用數字簡約表示以上三種標記,分別爲 10-1

示例如下:

import cv2
# 加載一張位於當前目錄下的`images/girl.jpg`的圖片
image_path = "images/girl.jpg"
# 以灰度模式讀取圖片
img = cv2.imread(image_path,0)

3.展示圖片

讀取圖片之後,可以將圖片展示到窗口。使用cv2.imshow()在窗口展示圖片。
函數聲明爲:

imshow(窗口名稱, 圖片對象)
  • 第一個參數傳入窗口的名字;
  • 第二個參數傳入需要展示的圖片對象。

當窗口展示完之後,需要再調用cv2.destroyAllWindows()銷燬所有的窗口。
示例如下:

import cv2

# 讀取圖片
image_path = "images/girl.jpg"
img = cv2.imread(image_path,1)

# 窗口展示圖片
cv2.imshow('cute girl',img)
# 等待用戶關閉圖片窗口
cv2.waitKey(0)
# 銷燬創建的所有窗口
cv2.destroyAllWindows()

運行上面的示例代碼會呈現下面的效果:

4.保存圖片

在完成圖像的一系列操作之後,可以使用cv2.imwrite()將圖片保存到本地。
函數聲明爲:

cv2.imwrite(圖片路徑, 圖片對象)
  • 第一個參數爲圖片路徑,圖片應該在當前的工作路徑,或在指定的絕對路徑下;
  • 第二個參數爲將要保存的圖片對象。

示例如下:

import cv2

# 讀取圖片
image_path = "images/girl.jpg"
img = cv2.imread(image_path,1)

# 保存圖片爲girl-copy.png
cv2.imwrite('images/girl-copy.png',img)

色彩空間及其轉換

你需要掌握:

  1. 什麼是色彩空間;
  2. 如何轉換色彩空間。

色彩空間

  • 色彩空間(Color space)是對色彩的組織方式,是座標系統和子空間的闡述,位於系統的每種顏色都有單個點表示。

  • 目前,色彩空間已經有上百種表示方式,被採用的大多數色彩空間都是面向硬件或面向應用的,大部分只是局部的改變或專用於某一領域。

  • 下面介紹一些常用的色彩空間。

RGB色彩空間

  • 我們知道,可以使用紅色、綠色和藍色這三種原色生成不同的顏色,這些顏色可以組成了一個色彩空間,稱爲RGB(Red Green Blue)色彩空間。

  • RGB是依據人眼識別的顏色定義出的空間,可表示大部分顏色。它是最通用的面向硬件的色彩空間。該色彩空間用於彩色監視器和一大類彩色視頻攝像。

  • 在該色彩空間中,將藍色的量定義爲X座標軸、紅色的量定義爲Y座標軸、綠色的量定義爲Z座標軸,就可以得到一個三維空間。所以每種顏色在這個三維空間中都有唯一的一個點與其對應。

完整的RGB色彩空間圖如下:

OpenCV中默認的色彩空間是BGR。BGR與RGB的區別只是三個顏色信道的位置發生了變化,實際上原理相同。

爲什麼是BGR而不是RGB呢?原因在於當時主流的攝像頭製造商和軟件供應商都普遍使用這種BGR格式,所以所以一開始時OpenCV採用的就是BGR,然後沿用至今。

HSV與HSL色彩空間

在科學研究一般不採用RGB色彩空間,它將色調,亮度,飽和度三個量放在一起表示,很難分開,這樣難以對其進行數字化的調整。所以爲了更好的數字化處理顏色,提出了HSV,HSL兩個色彩空間。

  • HSV色彩空間中,H是色調(hue),S是飽和度(saturation), V是明度(value)。

  • HSL色彩空間中,H是色調(hue),S是飽和度(saturation),L是亮度(lightness)。

灰度空間

在OpenCV的灰度空間中,和一般的色彩空間相同,每一個顏色都有三個量,但是隻有第一個亮度有值,所以表示爲(亮度,0,0)。
其中,亮度是根據如下灰度公式計算而得:

Gray = R*0.299 + G*0.587 + B*0.114

爲什麼人臉識別需要先對圖片進行灰度處理?

  • 識別人臉,最關鍵的因素是梯度,梯度代表着邊緣,用灰度圖計算梯度,可以簡化矩陣, 提高運算速度。

  • 而顏色信息,很容易受到光照等因素的影響,同類的物體顏色有很多變化,所以顏色本身難以提供關鍵信息。

色彩空間轉換

在OpenCV中有超過150種色彩空間轉換的方法。但是我們經常用到的是以下兩種:

  1. BGR空間到Gray空間 的轉換;
  2. BGR空間到HSV空間 的轉換。

使用的函數聲明爲:

cv2.cvtColor(圖片對象,轉換類型)

轉換類型,

  • 對於BGR到Gray的轉換,使cv2.COLOR_BGR2GRAY類型。
  • 對於BGR到HSV的轉換,使用cv2.COLOR_BGR2HSV類型。

示例如下:

# 將圖片的色彩空間由BGR轉換爲HSV
# 執行後output_img的色彩空間變成了HSV
output_img = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

我們也可以通過以下代碼獲取到OpenCV提供的所有轉換類型:

import cv2
flags = [i for in dir(cv2) if i startswith('COLOR_')]
print(flags)

基於Harr特徵的人臉檢測分類器

  • OpenCV的人臉檢測,使用Harr分類器。
  • 該分類器採用的Viola-Jones人臉檢測算法。它是在2001年由Viola和Jones提出的基於機器學習的人臉檢測算法。
  • 算法首先需要大量的積極圖片(包含人臉的圖片)和消極圖片(不包含人臉的圖片)。然後從中提取類Harr特徵( Harr-like features),之所以稱爲 Harr分類器,正是因爲它使用了類Harr特徵。
  • 最後,訓練出一個級聯檢測器,用其來檢測人臉。

類Harr特徵

  • 圖像中的特徵 通常是指,圖片的像素點經過一系列的運算之後得到的結果,這些結果可能是向量、矩陣和多維數據等等。
  • 類Harr特徵 是一種反映圖像的灰度變化的,像素分模塊求差值的一種特徵。

Harr特徵類別

它分爲三類:邊緣特徵、線性特徵、中心特徵和對角線特徵。用黑色兩種矩形框組成爲特徵模板。

  • 邊緣特徵:
  • 線性特徵:
  • 中心特徵和對角線特徵:

特徵值計算

例如,對於4x4的像素塊。

理想情況下,黑色和白色的像素塊分佈如下:

符合邊緣特徵的情況(a)。

但是通常情況,一張灰階照片的黑白分佈並非如此的明顯,例如:

根據公式,

第一張圖特徵值爲1,第二張圖特徵值爲0.75-0.18=0.56。

一張圖中,對於識別人臉,只有部分特徵是有效的。例如,用下圖中的特徵模板可以看出,眉毛區域比額頭要亮,鼻樑區域比眼鏡區域要亮。嘴脣區域比牙齒區域要暗。這樣的類Harr特徵能很好的識別出人臉。

爲簡化特徵值計算,可以使用積分圖算法。得到類Harr特徵後,使用AdaBoost的方法選擇出有效特徵。最後再使用瀑布型級聯檢測器提高檢測速度。其中,瀑布的每一層都是一個由Adaboost算法訓練得到的強分類器。

Harr人臉檢測一個簡單的截圖程如下:

紅色的搜索框不斷移動,檢測出是否包含人臉。一般來說,輸入的圖片會大於樣本,爲了檢索出不同大小的目標,分類器可以按比例的改變自己的尺寸,對輸入圖片進行多次的掃描。

訓練Harr分類器

訓練 Harr 分類器的主要步驟如下:

  • 蒐集製作大量的“消極”圖像
  • 蒐集製作大量“積極”圖像,確保這些圖像中包含要檢測的對象
  • 創建“積極”向量文件
  • 使用 OpenCV 訓練 Harr 分類器

因爲訓練需要花費較多的資源和時間,所以我們學習時,先使用 OpenCV 中已經訓練好的 Harr 分類器。

使用Harr分類器檢測人臉

OpenCV 中的人臉訓練模型格式爲 XML,可以從 官網下載 。在此我們使用Harrcascade_frontalface_default.xml模型檢測人臉。

聲明分類器:

CascadeClassifier(模型文件路徑)

調用分類函數:

detectMultiScale(圖片對象,scaleFactor, minNeighbors, minSize)
  • 圖片對象:待識別圖片對象;
  • scaleFactor:圖像縮放比例;
  • minNeighbors:對特徵檢測點周邊多少有效點同時檢測,這樣可避免因選取的特徵檢測點太小而導致遺漏;
  • minSize:特徵檢測點的最小尺寸,可選參數。
    示例如下:
import cv2 as cv
# 讀取圖片
img = cv.imread('face.jpg')
# 轉換爲灰度圖片
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 人臉檢測器
face_cascade = cv.CascadeClassifier('Harrcascade_frontalface_default.xml')
# 識別人臉
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
    print(x,y,w,h)

其中,圖片座標系以左上角爲原點,x,y代表人臉區域左上角座標,w代表寬度,h代表高度。

如圖所示:

繪製人臉與人眼區域

你需要掌握:

  1. 如何用 OpenCV 在圖像上繪製矩形;
  2. 如何使用 OpenCV 繪製圖片中人臉區域;
  3. 使用 OpenCV 繪製人臉區域中眼睛區域。

OpenCV 繪製矩形

上面我們學習了通過 OpenCV 的 Harr 分類器檢測人臉,並輸出識別結果(x,y,w,h)。

圖片座標以左上角爲原點,(x,y)代表人臉區域左上角座標,w代表人臉區域的寬度(width),h代表人臉區域的高度(height)。

例如:

那麼,如何使用OpenCV將人臉區域繪製出來呢?

在 OpenCV 中,可以使用cv2.rectangle()在圖片中繪製矩形區域。

它的函數聲明爲:

cv2.rectangle(圖片對象,矩形左上角的座標點,矩形右下角的座標點,顏色(B,G,R),邊框線的粗度)

對於上圖的紅色人臉邊框,可以指定左上角座標爲(x,y),右下角座標爲(x+w,y+h),顏色設定紅色,邊框線粗度爲2。

示例代碼如下:

cv2.rectangle(img,(x,y),(x+w,y+h)(0,0,255),2)

使用OpenCV繪製圖片中人臉區域

使用 OpenCV 分類器檢測人臉之後,一張圖片中可能包含多個人臉,所以我們對每一個識別到的人臉都繪製對應的矩形框。

示例代碼如下:

ort cv2
# 讀取圖片
img = cv2.imread('images/girl.jpg')
# 轉換爲灰度圖片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 人臉檢測器
face_cascade = cv2.CascadeClassifier('path-of-haarcascade_frontalface_default.xml')
# 識別人臉
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
# 繪製人臉區域
for (x,y,w,h) in faces:
    cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2)
    #灰度圖片的臉部區域
    face_grays = gray[y:y+h, x:x+w]
    #原圖像的臉部區域
    face_areas = img[y:y+h, x:x+w]

識別效果如下:

使用OpenCV繪製人臉區域中眼睛區域

進一步,我們在識別人臉的基礎上,使用官方提供的path-of-haarcascade_eye.xml人眼檢測模型,識別出人眼並繪製到圖片上。

如果單獨使用OpenCV人眼檢測模型,來識別出整個圖片中的人眼區域,效果不是很好。

代碼如下:

import cv2
# 讀取圖片
img = cv2.imread('images/girl.jpg')
# 轉換爲灰度圖片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 人臉檢測器
face_cascade = cv2.CascadeClassifier('path-of-haarcascade_frontalface_default.xml')
# 識別人臉
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
# 繪製人臉區域
for (x,y,w,h) in faces:
    cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2)
    #灰度圖片的臉部區域
    face_grays = gray[y:y+h, x:x+w]
    #原圖像的臉部區域
    face_areas = img[y:y+h, x:x+w]
    eye_cascade = cv2.CascadeClassifier('path-of-haarcascade_eye.xml')
    # 識別人眼
    eyes = eye_cascade.detectMultiScale(gray)
    for (ex,ey,ew,eh) in eyes:
        # 繪製人眼
        cv2.rectangle(img,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

同樣的(ex,ey,ew,eh)中(ex,ey)代表眼睛區域的左上角座標,ew代表寬度,eh代表高度。

識別效果如下:

綠色爲識別的人眼框,可以看出有識別錯誤的地方。

所以,一般情況下,我們會先檢測出人臉區域,然後在人臉區域中使用眼睛區域檢測模型得到眼睛區域,進而繪製。

示例代碼如下:

import cv2
# 讀取圖片
img = cv2.imread('images/girl.jpg')
# 轉換爲灰度圖片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 人臉檢測器
face_cascade = cv2.CascadeClassifier('path-of-haarcascade_frontalface_default.xml')
# 識別人臉
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
# 繪製人臉區域
for (x,y,w,h) in faces:
    cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2)
    #灰度圖片的臉部區域
    face_grays = gray[y:y+h, x:x+w]
    #原圖像的臉部區域
    face_areas = img[y:y+h, x:x+w]
    eye_cascade = cv2.CascadeClassifier('path-of-haarcascade_eye.xml')
    eyes = eye_cascade.detectMultiScale(face_grays)
    for (ex,ey,ew,eh) in eyes:
        # 在原圖像的臉部區域繪製眼睛區域
        cv2.rectangle(face_areas,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

識別效果如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章