- 文章內容提取自 人臉識別系統 —— OpenCV人臉檢測
- 人臉識別專欄:傳送門
OpenCV是一個開源的跨平臺計算機視覺庫。
學習目標是:
- 學會使用 OpenCV中一系列的圖像操作(採集圖片、讀取圖片、展示圖片以及保存圖片);
- 理解色彩空間,並使用 OpenCV進行色彩空間轉換;
- 理解 Harr分類器原理,使用 OpenCV中的 Harr分類器進行人臉檢測。
OpenCV是一個開源的跨平臺計算機視覺庫。跨平臺是指,它可以運行在Linux、Windows、Android和Mac OS等操作系統上。它實現了圖像處理和計算機視覺方面的很多通用算法,具有輕量高效的特點。OpenCV提供了多種語言的編程接口,例如C、C++、Python。
完整的人臉識別流程,一般有如下五個步驟:
- 圖像採集:使用攝像機或攝像頭採集含有人臉的圖像或視頻流;
- 人臉檢測:檢測圖片中是否包含人臉;
- 預處理:對人臉圖像進行灰度處理、噪聲過濾等預處理;
- 特徵點提取:提取人臉圖片中包含的特徵數據;
- 人臉識別:將新的人臉照片與人臉庫進行算法匹配,輸出識別結果。
圖片基本操作
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通道:控制透明度) -
也可以,使用數字簡約表示以上三種標記,分別爲
1
,0
或-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)
色彩空間及其轉換
你需要掌握:
- 什麼是色彩空間;
- 如何轉換色彩空間。
色彩空間
-
色彩空間(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種色彩空間轉換的方法。但是我們經常用到的是以下兩種:
- BGR空間到Gray空間 的轉換;
- 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代表高度。
如圖所示:
繪製人臉與人眼區域
你需要掌握:
- 如何用 OpenCV 在圖像上繪製矩形;
- 如何使用 OpenCV 繪製圖片中人臉區域;
- 使用 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)
識別效果如下: