1. 程式人生 > >訓練自己的人臉檢測分類器(級聯+LBP的Matlab的實現)

訓練自己的人臉檢測分類器(級聯+LBP的Matlab的實現)

本文通過MATLAB實現,能夠實時檢測識別到人臉,與OpenCV模型檔案相容,版本最好matlab2017a及其以上,老版本沒試過。本文主要分為3個步驟:(1)攝像頭獲取人臉正樣本影象;(2)攝像頭獲取負樣本影象;(3)訓練識別部分,可選擇從圖片,視訊,攝像頭實時識別。

注意事項:

(a)其中變數isSample=1時,即首次執行需要採集人臉影象,以後請把isSample置為0,表示以後不需要採集正樣本;(b)負樣本產生我寫在另一個函式createNegativeImgs()裡面,大家執行它即可,負樣本一定不要有你自己的人臉影象哦~ (c)importdata()函式用於把正樣本的標記檔案匯入到MATLAB工作空間中,請注意格式。

正樣本可以自己手動標記人臉框,可以從trainingImageLabeler  APP互動工具獲得,當然方便起見,我 從已有的人臉檢測器xml檔案檢測人臉,從而直接得到人臉正樣本,當然可以匯入到trainingImageLabeler  檢視預覽(注意格式),我這裡直接用的是lbpcascade_frontalface.xml分類器。

直接上程式碼,如下;

%% 用xml預訓練的分類器對人臉進行篩選,記錄人臉,用於訓練,測試
cam = webcam();% 攝像頭介面,沒有的話從matlab central網站搜尋下載

%% 收集樣本
isSample = 0; %這裡如果現場從攝像頭獲取你的影象作為訓練樣本,請把該值置為1
if isSample==1
    fig = figure;
    axes('parent',fig)
    detector = vision.CascadeObjectDetector('lbpcascade_frontalface.xml');
    detector.MinSize = [110,110];    
    videoPlayer = vision.VideoPlayer;
    
    % 人臉檢測與標記
    if ~exist('images','file') %當前目錄是否存在images資料夾,沒有則新建
        mkdir images
    end
    fid = fopen('images/face_rect.txt','a');% 以追加的方式進行寫入
    while  ishandle(fig)
        filename = [cd,'/images/',datestr(now,'yyyy-mm-dd-HH-MM-SS-FFF'),'.png'];
        frame = snapshot(cam);
        bbox = step(detector,frame);
        imwrite(frame,filename);
        fprintf(fid,'%s  %5d%5d%5d%5d \r\n',filename,bbox);
        if isempty(bbox)
            fprintf(fid,'\r\n');
        end
        
        positions = bbox;
        nums = size(positions,1);
        strLabels = {'face'};%strEye = repmat({'eye'},1,nums-1);       
        RGB = insertObjectAnnotation(frame,'rectangle',positions,strLabels,'color','g');
        step(videoPlayer,RGB);
    end
    fclose(fid);  
end

%% 不需要訓練
facerect1 = importdata();
imageNames = cellstr(facerect1.imagenames);
rects = [facerect1.x,facerect1.y,facerect1.w,facerect1.h];

faceRect = table(imageNames,rects,'VariableNames',{'imageFilename','face'});
index = ~isnan(rects(:,1));
faceTrain = faceRect(index,:);
% faceRect.imageNames = cellstr(imageNames);
% faceRect.rects = rects;%mat2cell(rects,ones(1,length(labels.imageNames)));
num = length(faceTrain.imageFilename);

%% 正樣本製作
trainPosNums = 500; % 這裡設定你的訓練正樣本數量,根據你的樣本量適當選擇
newTrainLabels = faceTrain(randi(num,1,trainPosNums),:); %table型別


%% 負樣本製作
trainNegNums = 500; % 這裡設定你的訓練負樣本數量,根據你的樣本量適當選擇
negativeImgDataStore = imageDatastore(fullfile(cd,'NegativeImgs'));
negNUM = length(negativeImgDataStore.Files);
negativeImages = negativeImgDataStore.Files( randi(negNUM,1,trainNegNums) );

%% 開始訓練
xmlName = 'myLBPfaceDetector.xml';
trainCascadeObjectDetector(xmlName,newTrainLabels,negativeImages,...
    'FalseAlarmRate',0.1,'NumCascadeStages',20,...
    'FeatureType','LBP');

%% test ,選擇跑的內容
detector = vision.CascadeObjectDetector(xmlName);
detector.MinSize = [100 ,100];
detector.MergeThreshold = 4;
videoPlayer = vision.VideoPlayer;

%% flag選擇平臺,flag = 0為跑圖片,flag = 1為跑視訊檔案,flag=2為跑攝像頭
flag = 2;% 選擇

index = 0;
if flag == 0 %跑圖片
    imdsTest = imageDatastore('F:\video\patform_data\6月\06',... 
        'includeSubfolder',true);%圖片檔案,這裡設定你自己的測試人臉影象路徑
    for i  = 1:length(imdsTest.Files)
        imageTest = readimage(imdsTest,i);
        bbox = step(detector,imageTest);
        RGB = insertObjectAnnotation(imageTest,'rectangle',bbox,'face');
        step(videoPlayer,RGB);
        index = index+1;
        disp(index);
    end
elseif flag == 1 % 跑視訊
    obj = vision.VideoFileReader('F:\video\smokeVideo2017_3_1\170405151456_1280328332795.mp4');%注意這裡是你自己的視訊檔案路徑
    while ~isDone(obj)
        frame = step(obj);
        bbox = step(detector,frame);
        if ~empty(bbox)
            RGB = insertObjectAnnotation(frame,'rectangle',bbox,'face');
        else
            RGB = frame;
        end
        step(videoPlayer,RGB);
        index = index+1;
        disp(index);
    end
elseif flag == 2 % 跑攝像頭
    while 1 % command Window按ctrl+c終止迴圈
        frame = snapshot(cam);
        bbox = step(detector,frame);
        RGB = insertObjectAnnotation(frame,'rectangle',bbox,'face');
        step(videoPlayer,RGB);      
    end
else
    disp('your input may be wrong!');
end


另外importdata()函式和createNegativeImgs()函式如下:
function faceRect = importdata()
%% Initialize variables.
filename = 'E:\MATLAB\trainMyCascadeFace\images\face_rect.txt';
delimiter = ' ';

%% Format for each line of text:
%   column1: text (%s)
%	column2: double (%f)
%   column3: double (%f)
%	column4: double (%f)
%   column5: double (%f)
% For more information, see the TEXTSCAN documentation.
formatSpec = '%s%f%f%f%f%[^\n\r]';

%% Open the text file.
fileID = fopen(filename,'r');

%% Read columns of data according to the format.
% This call is based on the structure of the file used to generate this
% code. If an error occurs for a different file, try regenerating the code
% from the Import Tool.
dataArray = textscan(fileID, formatSpec, 'Delimiter', delimiter, 'MultipleDelimsAsOne', true, 'TextType', 'string', 'EmptyValue', NaN,  'ReturnOnError', false);

%% Close the text file.
fclose(fileID);

%% Post processing for unimportable data.
% No unimportable data rules were applied during the import, so no post
% processing code is included. To generate code which works for
% unimportable data, select unimportable cells in a file and regenerate the
% script.

%% Create output variable
facerect1 = table(dataArray{1:end-1}, 'VariableNames', {'imagenames','x','y','w','h'});

%% Clear temporary variables
clearvars filename delimiter formatSpec fileID dataArray ans;
faceRect = facerect1;

-------------------------------------------------分割線-------------------------------------------

function createNegativeImgs()

cam = webcam();

if ~exist('NegativeImgs','file')
    mkdir NegativeImgs
end

videoPlayer = vision.VideoPlayer();
index = 0;
while 1
    filename = [cd,'/NegativeImgs/',datestr(now,'yyyy-mm-dd-HH-MM-SS-FFF'),'.png'];
    frame = snapshot(cam);
    imwrite(frame,filename);
    step(videoPlayer,frame);
    index = index+1;
    disp(index);
end
最後給出我檢測自己人臉效果圖:D,打成馬賽克啦~

  RGB = insertShape(frame,'FilledRectangle',bbox,'Opacity',1,'color','red');