1. 程式人生 > >opencv學習筆記五十三:訓練自己的級聯分類器

opencv學習筆記五十三:訓練自己的級聯分類器

訓練工作主要分為如下幾步:

  • 配置訓練環境
  • 製作訓練資料集
  • 獲取樣本路徑列表
  • 生成正樣本描述檔案(.vec)
  • 訓練人臉分類器 
  • 使用分類器進行人臉檢測

配置訓練環境 

 訓練過程主要依靠OpenCV自帶的兩個可執行程式opencv_createsamples.exeopencv_haartraining.exe操作完成的。新建一個資料夾命名為cascadeTrain,將opencv3.4.1\opencv\build\x64\vc14\bin中的上面兩個可執行程式及兩個dll檔案拷到該資料夾下,如下圖:

製作訓練資料集

1、準備正樣本:這裡只是熟悉一下怎麼訓練自己感興趣的東西,所以我還是進行簡單的人臉訓練,首先在網上下載了yale大學的人臉資料庫,由耶魯大學計算視覺與控制中心建立,包含15位志願者的165張圖片,包含光照,表情和姿態。下載網址為:

http://vismod.media.mit.edu/vismod/classes/mas622-00/datasets/。下載的人臉資料如下所示:

 按住ctrl+A全選,重新命名第一張影象為(1),後面所有的影象會自動升序重新命名,如下所示:

 圖片中還有白的背景頭髮等,訓練人臉最好只有臉部,所以我先用matlab中的級聯人臉檢測將上述圖片中的人臉檢測出來,並統一尺寸為24*24的(opencv推薦的),然後儲存為一組新的只包含臉部的圖片,將其作為我們的正樣本資料集。在cascadeTrain資料夾下新建posdata資料夾,將正樣本資料集放入其中。

temp = 'C:\Users\Administrator\Desktop\cascadeTrain\';
for i = 1:165
    path1 = strcat(temp,'yalefaces\','(',num2str(i),')','.gif');
    I = imread(path1);    
    %人臉檢測     
    faceDetector = vision.CascadeObjectDetector; 
    bboxes = step(faceDetector, I);
    I = imcrop(I,bboxes);%將檢測到的人臉區域bboxes從原圖中裁剪出來
    %尺寸歸一化
    I = imresize(I,[24,24]);
    %將檢測到的人臉圖片另存為
    path2 = strcat(temp,'posdata\','(',num2str(i),')','.bmp');
    imwrite(I,path2);  
end

 生成的臉部影象如下所示:

2、準備負樣本:這裡我採用的負樣本是用的是weizmann團隊網站上的影象分割資料庫,裡面有灰色圖和彩色圖,這裡當然選取灰度圖了。下載網址為http://www.wisdom.weizmann.ac.il/~vision/Seg_Evaluation_DB/dl.html。用matlab遍歷出文件夾下所有灰度圖作為負樣本資料集。在cascadeTrain資料夾下新建negdata資料夾,將負樣本資料集放入其中。

temp = 'C:\Users\Administrator\Desktop\cascadeTrain\';
for i = 1:200
    path1 = strcat(temp,'nonface\','(',num2str(i),')','\src_bw\');
    imgdir = dir([path1,'*.png']);%遍歷該資料夾下所有png格式檔案
    for j=1:length(imgdir)
        I = imread([path1,imgdir(j).name]);
        %另存為bmp格式
        path2 = strcat(temp,'negative\','(',num2str(i),')','.bmp');
        imwrite(I,path2);  
    end    
end

這裡用了200幅圖片,負樣本中不能含有人臉且準備的數目必須要比正樣本多,大小大約在300*200畫素,負樣本尺寸不用歸一化,截圖如下所示:

 獲取樣本路徑列表

先進入正樣本資料的目錄下(posdata目錄),新建一個文字文件posdir.txt,然後編輯文字如下:

     編輯完成後退出儲存,然後把副檔名修改為bat(dos系統批處理的檔案格式),,雙擊該檔案,就會在該目錄下生成一個posdata.txt,如下:

       開啟num.txt,使用文字編輯器的替換功能,做一些替換工作 

       替換1:將絕對路徑替換成相對路徑

       

        替換2:1代表該圖片中有幾張人臉,後四個分別對應人臉起點座標及寬和高

       

       將替換好的posdata.txt複製到posdata目錄的同級目錄下。

       同理,負樣本的路徑列表按照上述方法進行,替換時只需要將絕對路徑改為相對路徑即可,將替換好的negdata.txt複製到negdata目錄的同級目錄下。

生成正樣本描述檔案(.vec)

 樣本描述檔案就是一個.vec檔案,為opencv訓練準備的,只有正樣本需要,負樣本不需要。 開啟cmd.exe,強制進入到工作目錄下用cd /d

檢視opencv_createsamples.exe引數

  • -info 正樣本路徑列表,這裡為-info posdata.txt
  • -vec 生成的vec檔名,這裡取-vec posdata.vec
  • -bg  負樣本路徑列表,這裡為-bg negdata.txt
  • -num 正樣本數量,如實填寫,我這裡為-num  165  
  • -w -h 正樣本的尺寸,它預設為-w 24 -h 24  

其它引數不用填,預設就好,執行以下命令在cascadeTrain資料夾下就會生成一個posdata.vec的檔案 

訓練人臉分類器 

檢視opencv_traincascade.exe引數

  • -data:    先在cascadeTrain資料夾下建立一個haarxml的資料夾,將來生成的各級的xml檔案都將在裡面,-data haarxml
  • -vec:  剛才生成的樣本描述檔案,-vec posdata.vec
  • -numPos 用於訓練的正樣本數量,這裡填的要比實際正樣本少,因為每一級都可能有誤分類,即將正樣本當成負樣本,則在下一級中該正樣本就不能用了,所以要留點餘量,-numPos 155
  • -numNeg 用於訓練的負樣本數量,這裡可以比實際負樣本大,它會自動從你負樣本中不斷地各種裁剪,-numNeg 600
  • -numStages 指定訓練層數(決策樹),推薦15~20,層數越多,錯誤率越低,耗時越長,-numStages 15
  • featureType 指定訓練什麼特徵,LBP比HAAR快很多,精度稍低,這裡訓練haar特徵,不用填,預設就好
其它引數不用填,預設就好,執行以下命令進行訓練,得到xml檔案

 訓練完成後,在haarxml資料夾下會生成各級的xml檔案,如下所示:

使用分類器進行人臉檢測

#include<opencv2\opencv.hpp>
using namespace cv;
using namespace std;

int main(int arc, char** argv) { 
	Mat src = imread("5.jpg");
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", src);
	Mat gray;
	cvtColor(src, gray, CV_BGR2GRAY);
	CascadeClassifier faceclassifier;
	faceclassifier.load("C:/Users/Administrator/Desktop/cascadeTrain/lbpxml/cascade.xml");//載入訓練好的xml檔案
	
	vector<Rect>objects;		
	faceclassifier.detectMultiScale(gray, objects, 1.1, 1, 0, Size(24, 24));
	for (int i = 0; i < objects.size(); i++) {
		rectangle(src, objects[i], Scalar(0, 255, 0), 2);
	}
	imshow("output", src);		
	waitKey(0);
	return 0;
}

 

 

 

可看到最後一張檢測不是很好,因為樣本資料實在是太少了,就一兩百個,實際應用中至少要訓練個四五千個吧,這裡考慮到訓練時間太久,只是做了個簡單的練習。