本期将介紹臉部檢測、眼睛檢測;圖像拉直、裁剪、調整大小、歸一化等内容

目前,涉及面部分類的計算機視覺問題,通常都需要使用深度學習。是以在将圖像輸入神經網絡之前,需要經過一個預處理階段,以便達到更好的分類效果。
圖像預處理通常來說非常簡單,隻需執行幾個簡單的步驟即可輕松完成。但為了提高模型的準确性,這也是一項非常重要的任務。對于這些問題,我們可以使用OpenCV完成:一個針對(實時)計算機視覺應用程式的高度優化的開源庫,包括C ++,Java和Python語言。
接下來我們将一起探索可能會應用在每個面部分類或識别問題上應用的基本原理,示例和代碼。
注意:下面使用的所有圖像均來自memes.。
圖檔載入
我們使用該imread()函數加載圖像,并指定檔案路徑和圖像模式。第二個參數對于運作基本通道和深度轉換很重要。
img = cv2.imread('path/image.jpg', cv2.IMREAD_COLOR)
要檢視圖像可以使用imshow()功能:
cv2.imshow(img)
如果使用的type(img)話,将顯示該圖像的尺寸包括高度、重量、通道數。
彩色圖像有3個通道:藍色,綠色和紅色(在OpenCV中按此順序)。
我們可以很輕松檢視單個通道:
# Example for green channel
img[:, :, 0]; img[:, :, 2]; cv2.imshow(img)
Grayscale version
灰階圖像
為了避免在人臉圖像分類過程中存在的幹擾,通常選擇黑白圖像(當然也可以使用彩圖!請小夥伴們自行嘗試兩者并比較結果)。要獲得灰階圖像,我們隻需要在圖像加載函數中通過将适當的值作為第二個參數傳遞來指定它:
img = cv2.imread('path/image.jpg', cv2.IMREAD_GRAYSCALE)
現在,我們的圖像隻有一個灰階通道了!
面部和眼睛檢測
在處理人臉分類問題時,我們可能需要先對圖形進行裁剪和拉直,再進行人臉檢測以驗證是否有人臉的存在。為此,我們将使用OpenCV中自帶的的基于Haar特征的級聯分類器進行對象檢測。
首先,我們選擇用于面部和眼睛檢測的預訓練分類器。以下時可用的XML檔案清單:
1)對于面部檢測,OpenCV提供了這些(從最松的先驗到最嚴格的先驗):
• haarcascade_frontalface_default.xml
• haarcascade_frontalface_alt.xml
• haarcascade_frontalface_alt2.xml
• haarcascade_frontalface_alt_tree.xml
2)對于眼睛檢測,我們可以選擇以下兩種:
• haarcascade_eye.xml
• haarcascade_eye_tree_eyeglasses.xml(正在嘗試處理眼鏡!)
我們以這種方式加載預訓練的分類器:
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + ‘haarcascade_frontalface_default.xml’)eyes_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + ‘haarcascade_eye.xml’)
我們可以測試幾種組合,但我們要記住一點,沒有一種分類器在所有情況下都是最好的(如果第一個分類失敗,您可以嘗試第二個分類,甚至嘗試所有分類)。
對于人臉檢測,我們可使用以下代碼:
faces_detected = face_cascade.detectMultiScale(img, scaleFactor=1.1, minNeighbors=5)
結果是一個數組,其中包含所有檢測到的臉部特征的矩形位置。我們可以很容易地繪制它:
(x, y, w, h) = faces_detected[0]
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 1);
cv2.imshow(img)
對于眼睛,我們以類似的方式進行,但将搜尋範圍縮小到剛剛提取出來的面部矩形框内:
eyes = eyes_cascade.detectMultiScale(img[y:y+h, x:x+w])for (ex, ey, ew, eh) in eyes:
cv2.rectangle(img, (x+ex, y+ey), (x+ex+ew, y+ey+eh),
(255, 255, 255), 1)
盡管這是預期的結果,但是很多時候再提取的過程中我們會遇到一些難以解決的問題。比如我們沒有正面清晰的人臉視圖。
不能正确檢測的案例
臉部旋轉
通過計算兩隻眼睛之間的角度,我們就可以拉直面部圖像(這很容易)。計算之後,我們僅需兩個步驟即可旋轉圖像:
rows, cols = img.shape[:2]
M = cv2.getRotationMatrix2D((cols/2, rows/2), <angle>, 1)
img_rotated = cv2.warpAffine(face_orig, M, (cols,rows))
裁臉
為了幫助我們的神經網絡完成面部分類任務,最好去除外界無關資訊,例如背景,衣服或配件。在這些情況下,面部裁切非常友善。
我們需要做的第一件事是再次從旋轉後的圖像中擷取面部矩形。然後我們需要做出決定:我們可以按原樣裁剪矩形區域,也可以添加額外的填充,以便在周圍獲得更多空間。這取決于要解決的具體問題(按年齡,性别,種族等分類);也許我們需要保留頭發,也許不需要。
最後進行裁剪(p用于填充):
cv2.imwrite('crop.jpg', img_rotated[y-p+1:y+h+p, x-p+1:x+w+p])
現在這張臉的圖像是非常單一的,基本可用于深度學習:
圖像調整大小
神經網絡需要的所有輸入圖像具有相同的形狀和大小,因為GPU應用相同的指令處理一批相同大小圖像,可以達到較快的速度。我們雖然可以随時調整它們的大小,但這并不是一個好主意,因為需要在訓練期間将對每個檔案執行幾次轉換。是以,如果我們的資料集包含大量圖像,我們應該考慮在訓練階段之前實施批量調整大小的過程。
在OpenCV中,我們可以與同時執行縮小和升頻resize(),有幾個插值方法可用。指定最終大小的示例:
cv2.resize(img, (<width>, <height>), interpolation=cv2.INTER_LINEAR)
要縮小圖像,OpenCV建議使用INTER_AREA插值法,而放大圖像時,可以使用INTER_CUBIC(慢速)或INTER_LINEAR(更快,但效果仍然不錯)。最後,這是品質和時間之間的權衡。
我對更新進行了快速比較:
前兩個圖像似乎品質更高(但是您可以觀察到一些壓縮僞像)。線性方法的結果顯然更平滑(沒有對比度)并且噪點更少(黑白圖像證明)。最後一個像素化。
歸一化
我們可以使用normalize()功能使視覺圖像标準化,以修複非常暗/亮的圖像(甚至可以修複低對比度)。該歸一化類型是在函數參數指定:
norm_img = np.zeros((300, 300))
norm_img = cv2.normalize(img, norm_img, 0, 255, cv2.NORM_MINMAX)
例子:
當使用圖像作為深度卷積神經網絡的輸入時,無需應用這種歸一化(上面的結果對我們來說似乎不錯,但是并不針對他們的眼睛)。在實踐中,我們将對每個通道進行适當的歸一化,例如減去均值并除以像素級别的标準差(這樣我們得到均值0和偏差1)。如果我們使用轉移學習,最好的方法總是使用預先訓練的模型統計資訊。
結論
當我們處理面部分類/識别問題時,如果輸入的圖像不是護照照片時,檢測和分離面部是一項常見的任務。
OpenCV是一個很好的圖像預處理任務庫,不僅限于此。對于許多計算機視覺應用來說,它也是一個很好的工具……
https://www.youtube.com/watch?v=GebcshN4OdE
https://www.youtube.com/watch?v=z1Cvn3_4yGo
https://github.com/vjgpt/Face-and-Emotion-Recognition