第三篇:基於深度學習的人臉特徵點檢測 - 資料集整理
https://yinguobing.com/facial-landmark-localization-by-deep-learning-data-collate/
在上一篇博文中,我們已經下載到了包括300-W、LFPW、HELEN、AFW、IBUG和300-VW在內的6個數據集,初步估算有25萬個樣本可以使用。同時還發現了一篇論文描述了採用深度神經網路來提取特徵點的方法。在本篇文章中,我們將嘗試對下載到的資料進行分析整理,包括:
- 統計資料集中不同格式檔案的數量。
- 提取視訊檔案中的每一幀為單獨的檔案。
- 從自定義格式pts檔案中讀取特徵點座標,並顯示在圖片上。
這些步驟將為後續的工作打下堅實的資料基礎。
檢查資料集的形式
為方便使用,大部分資料集都會盡可能的保留原始資料,並將附加的資訊以文字或者其它形式進行儲存,然後打包成一個或者若干壓縮文件。所以拿到資料集後的第一件事,就是閱讀資料集的說明文件。通過閱讀說明,我們發現這六個資料庫中的特徵點座標均以後綴名為pts
的格式進行儲存,且檔名與對應的圖片檔名相同。
有一個例外是300-VW。由於它是視訊資料庫,每一個視訊檔案則對應多個pts
檔案,每個pts
檔案對應了視訊中的某一幀。
開啟其中任意一個pts
檔案,發現檔案內容大概是這個樣子:
version: 1 n_points: 68 { 336.820955 240.864510 334.238298 260.922709 335.266918 283.697151 # 中間省略若干行 370.512631 329.910074 363.035791 328.132512 357.493721 327.074215 }
不難發現,每一個pts
檔案中第一行是檔案版本,第二行是座標個數說明,從第三行開始,括號記憶體儲的是對應影象中人臉的68個特徵點的座標x與y,一行一組。所以有多少個pts
檔案,就有多少個可用樣本。所以,我們究竟有多少個可用樣本?
使用Python統計檔案數量
在Linux系統下,統計檔案數量其實是非常簡單的事情。直接在資料夾上點選滑鼠郵件,選取Properties
即可看到資料夾下的檔案總數與大小。例如我這裡總共包含227827項,大小5.2GB。但是這並不能準確的告訴我們pts
檔案的個數。並且,為了對資料集獲得全面的認識,我們通常希望掌握資料夾下所有檔案的數量與分佈情況。這時候就該Python出場了!
為什麼用Python?作為“自帶電池”的計算機程式語言,Python提供了一系列模組可以極大的提升我們的工作效率,用盡可能少的程式碼快速的實現功能。對於統計檔案數量這個需求來說,我們可以簡單的使用幾個函式就實現。主要的思路是:
最後總體程式碼只有55行,包含了註釋與空行。你可以自己嘗試實現一下,也可以檢視我在Github上開源實現。
經過統計,當前資料集所包含的檔案數量與分佈情況如下:
Total files: 227587
zip: 1; txt: 1; jpg: 2802; png: 1635; pts: 223034; avi: 114; Done!
從中可以看到我們可以使用的樣本個數為223034個,即pts
檔案的個數。圖片以兩種格式儲存,jpg
格式2802個,png
格式1635個,兩者加起來才4437個。有20多萬個樣本都以視訊幀的形式儲存在114個avi
檔案中。
使用FFmpeg提取視訊幀
若要利用這20多萬個樣本,需要從視訊中提取每一幀影象為單獨的檔案。這裡我推薦使用著名的音視訊包FFmpeg[3]。
FFmpeg是一套完整的音視訊轉換與流媒體開源解決方案。在Ubuntu下你可以簡單的通過apt
命令來安裝它。FFmpeg的使用也很簡單,在終端中輸入以下命令即可將視訊中的每一幀提取成為單獨的影象檔案,存放在當前目錄的image
資料夾下,檔名取自幀編號:
ffmpeg -i vid.avi -qscale:v 1 -f image2 image/%06d.jpg
其中-i
是指定輸入檔案,-qscale:v
是指定輸出的圖片質量引數,-f
為輸出檔案的模式。如果不指定-qscale:v
的話FFmpeg會使用預設引數輸出,圖片質量會變得很差[4]。下圖從左向右依次是預設引數,質量為1和不壓縮的BMP格式。
由於300-VW下的114個avi
視訊檔案檔名是相同的,我們可以寫一個簡單的Shell指令碼來批量將avi
視訊中的幀提取出來。
for dir in $(ls -d */);
do
cd $dir;
mkdir image;
ffmpeg -i vid.avi -qscale:v 1 -f image2 image/%06d.jpg;
cd ..;
done
這段指令碼在執行過程中會輸出log供參考。整個300-VW的轉換在我的計算機上花費的時間不到10分鐘。
轉換完成後,我們可以使用之前建立好的檔案統計指令碼重新統計檔案數量。
Total files: 446185
jpg: 221399; txt: 1; pts: 223034; png: 1635; zip: 1; sh: 1; avi: 114; Done!
將jpg
的數量221399與png
的數量1635加起來是223034,剛好等於pts
檔案的數量。
So far so good!不過,這些圖片與pts
中的座標能對應上嗎?
驗證特徵點座標與圖片的一致性
理論上圖片與座標資料是一一對應的,不過我相信你心裡應該也會有那麼一點點的不確定——同名的pts
與影象檔案真的一一對應嗎?我們從視訊中提取出來的影象呢,也能對應上嗎?
為了消除心中的這個疑慮,也是為了從最開始就排除資料不匹配這一最糟糕的情況,最好將資料中的特徵點畫在對應影象上,人工用肉眼來驗證一下!
要達成這一目標,需要實現以下兩個主要功能:
- 從
pts
檔案中讀取68個特徵點的座標。 - 讀取對應的影象,將特徵點繪製在影象上並呈現出來。
使用Python讀取文字檔案
Python讀取文字文件是不能再簡單的事情,使用以下3行程式碼即可逐行打印出文字文件中的所有內容[5]。
with open('image_003_1.pts') as file:
for line in file:
print(line)
使用該方法將一個pts
檔案中的內容打印出來如下:
version: 1
n_points: 68
{
336.820955 240.864510
334.238298 260.922709
335.266918 283.697151
# 中間省略若干行
370.512631 329.910074
363.035791 328.132512
357.493721 327.074215
}
仔細觀察不難發現,68個特徵點在pts
檔案中是順序儲存的,一行一組,所以只需要排除掉非座標點行即可得到所有座標。具體的排除方法可以自選,例如座標行中僅包含數字、小數點和空格,非座標行的字元與符號幾乎是固定的。稍微留意一下方法的穩健性與通用性即可。如果你想也可以參考下我在Github上的實現方法[6]。
使用Python讀取並顯示圖片
在這裡,我推薦使用適用於Python的OpenCV模組。你可以通過pip
方式安裝,也可以按照官方教程[7]自行編譯。
安裝完成後,我們就可以使用Python呼叫OpenCV函式,主要是以下3個:
cv2.imread()
讀取影象檔案。cv2.circle()
在影象指定位置處繪製圓點。cv2.imshow()
將修改後的影象顯示在視窗中。
具體實現過程並不複雜,你可以自己嘗試一下,同樣也可以參考我在Github上的實現方法[6:1]。
最後,我們從蒐集好的6個數據集中隨機選擇一些檔案來看一下效果。
300-VW
300-W
AFW
HELEN
HELEN資料集中的圖片解析度較高,因此繪製的Mark點看上去很小。
IBUG
LFPW
同樣需要注意的是有時候圖片中存在多張人臉,但是一個pts
檔案中只儲存一個人臉的資料。
看上去還不錯,是吧!
接下來的工作
至此我們已經將資料集整理並驗證完成。如果你有耐心,可以把所有的資料集都過一遍,你會發現資料集中的圖片有大有小,樣本人群多種多樣,眼鏡、首飾等等遮擋情況不時發生。總體看來這些都是不錯的訓練樣本,不過也給我們後邊的工作帶來了一些麻煩。如果人臉只佔圖片中的一小部分,卻將整張圖片送入神經網路,然後要求學習特徵點座標,這意味著神經網路需要學習非常複雜的規則,花精力去區分非人臉部分,意味著網路的複雜度會提高,意味著引數的數量會上升,意味著需要更多的訓練樣本,更長的訓練時間,以及最後在應用時更慢的執行速度。所以,我們怎麼辦?
這是我們在下一篇博文中要解決的問題:定義檢測規則,並提取適合神經網路的訓練樣本。