做者|Jaime Duránx
編譯|Flin
來源|mediumhtml
目前我正在研究一個涉及面部分類的計算機視覺問題。這一般意味着應用深度學習,所以在將圖像注入到咱們的神經網絡以前須要一個特殊的預處理階段。java
爲了提升咱們的模型精度,這是一項很是重要的任務,經過如下幾個簡單的步驟能夠很容易地完成。對於本文,咱們可使用OpenCV:一個高度優化的計算機視覺開源庫,在C++、java和Python中可用。python
這是一篇簡短的文章,包含了一些基本的指導原則、示例和代碼,你可能須要將它們應用到每一個面部分類或識別問題上。git
注意:本文中使用的全部靜態圖像都來自 https://imgflip.com/memetemplatesgithub
咱們將使用imread()
函數加載圖像,指定文件的路徑和mode。第二個參數對於動態運行基本通道和深度轉換很是重要。數組
img = cv2.imread('path/image.jpg', cv2.IMREAD_COLOR)
要查看圖像,咱們有imshow()
函數:網絡
cv2.imshow(img)
若是你寫的是類型(img),你會看到尺寸是(height, weight, channels)。機器學習
咱們的彩色圖像有3個通道:藍色,綠色和紅色(在OpenCV中按這個順序)。ide
咱們能夠輕鬆查看單個通道:函數
# Example for green channel img[:, :, 0]; img[:, :, 2]; cv2.imshow(img)
爲了不在面部圖像分類中分心,使用黑白圖片是個好主意(也可能不是!)你能夠二者都試試)。爲了獲得灰度版本,咱們只須要在圖像加載函數中指定,將適當的值做爲第二個參數傳遞:
img = cv2.imread('path/image.jpg', cv2.IMREAD_GRAYSCALE)
如今咱們的圖像有了一個單獨的通道!
當處理面部分類問題時,咱們可能想要作面部檢測,以驗證(是否有臉?),裁剪和拉直咱們的圖像。咱們將使用OpenCV中包含的基於Haar特性的級聯分類器進行對象檢測。(https://docs.opencv.org/2.4/modules/objdetect/doc/cascade_classification.html)
首先,咱們選擇預先訓練的人臉和眼睛檢測分類器。有一個可用的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_eyegasses.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)
成啦!
雖然這是預期的結果,但咱們會遇到不少其餘方面的問題。不少時候,咱們沒有正面和清晰的人的臉,甚至……
沒有眼睛:
眼睛是被白色包圍的黑色污點:
此處有4隻眼,僅檢測到3隻眼:
經過計算兩隻眼睛之間的角度,咱們能夠拉直臉部圖像(這很容易)。計算後,咱們僅需兩個步驟便可旋轉圖像:
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()
函數應用視覺歸一化,以修復很是暗/亮的圖片(甚至能夠修復低對比度)。
該歸一化類型(https://docs.opencv.org/3.4/d2/de8/group__core__array.html#gad12cefbcb5291cf958a85b4b67b6149f) 在函數參數中指定:
norm_img = np.zeros((300, 300)) norm_img = cv2.normalize(img, norm_img, 0, 255, cv2.NORM_MINMAX)
例子:
當使用圖像做爲深度卷積神經網絡的輸入時,不須要應用這種歸一化。
在實踐中,咱們將對每一個通道進行適當的歸一化,好比減去平均值,而後除以像素級的標準差(所以咱們獲得平均值0和誤差1)。若是咱們使用遷移學習,最好的方法老是使用預先訓練的模型統計數據。
在處理人臉分類/識別問題時,若是輸入的圖像不是護照圖片,則檢測和分離出人臉是一項常見的任務。
OpenCV是一個很好的圖像預處理庫,但不只僅如此。它也是一個強大的工具,爲許多計算機視覺應用…
來看文檔吧!
但願你喜歡這篇文章!
歡迎關注磐創AI博客站:
http://panchuang.net/
sklearn機器學習中文官方文檔:
http://sklearn123.com/
歡迎關注磐創博客資源彙總站:
http://docs.panchuang.net/