基於深度學習的車輛檢測系統(MATLAB程式碼,含GUI介面)

功能演示動圖

摘要:當前深度學習在目標檢測領域的影響日益顯著,本文主要基於深度學習的目標檢測演算法實現車輛檢測,為大家介紹如何利用\(\color{#4285f4}{M}\color{#ea4335}{A}\color{#fbbc05}{T}\color{#4285f4}{L}\color{#34a853}{A}\color{#ea4335}{B}\)設計一個車輛檢測系統的軟體,通過自行搭建YOLO網路並利用自定義的數據集進行訓練、驗證模型,最終實現系統可選取圖片影片進行檢測、標註,以及結果的實時顯示和保存。其中,GUI介面利用最新的MATLAB APP設計工具開發設計完成,演算法部分選擇時下實用的YOLO v2/v3網路,通過BDD100K數據集進行訓練、測試檢測器效果。本文提供項目所有涉及到的程式程式碼、數據集等文件,完整資源文件請轉至文末的下載鏈接,本博文目錄如下:

➷點擊跳轉至文末所有涉及的完整程式碼文件下載頁☇


完整資源下載鏈接//mianbaoduo.com/o/bread/YZaal55t

介紹及演示影片鏈接://www.bilibili.com/video/BV1oh411k7q7/(歡迎關注部落客B站影片)

程式碼使用介紹及演示影片鏈接://www.bilibili.com/video/BV1No4y197rW/


前言

    如今機器視覺領域深度學習演算法已經大行其道,也讓人工智慧的實現不再那麼遙不可及,但是在目標檢測領域,讓電腦超越人類還需讓更多的人參與進來繼續努力。如今眾多的高校,甚至中小學已經將人工智慧納入了學習科目,這確實能讓人感受到AI的魅力以及社會對其重視程度。研究、學習及從事AI技術已近5年,部落客自認為對其中的基本知識也算學到點皮毛,因此這裡開一個目標檢測專欄,根據自己的經驗提供點實例幫助大家入門了。

    印象中玩深度學習彷彿用的都是Python,但其實現在MATLAB也是可以的,並且玩得也不賴。由於高校幾乎普遍青睞MATLAB,恐怕很多人最熟悉的程式語言要屬它了。在網上查閱了很久,利用MATLAB實現的這類程式屬實不多,因此用它來寫一個Demo就有必要了。


1. 效果演示

    詳細介紹前還是先看看整體效果吧,畢竟品質不高的資源網上多得是,沒啥吸引力的恐怕大家看都不想看了。先上幾個動圖看看介面了,介面中默認裝載了部落客訓練好的模型,選擇一張圖片可標記出目標並顯示標記框位置、識別類型及置信度值,GUI介面如下圖所示:

功能演示動圖

    識別出的圖片結果可通過顯示介面右上角上的菜單欄選擇另存為圖片文件,將帶有識別框的圖片保存到自己的電腦上。另外介面可實現縮放、拖動等常見圖片處理功能,展示介面如下:

功能演示動圖

    選擇一個影片格式的文件可對影片進行逐幀檢測,在影片中標註出檢測結果顯示在介面上,最終檢測完成的影片文件默認保存在當前文件夾下,該功能的展示介面如下:

功能演示動圖

    本項目所有功能在MATLAB R2020b中已測試通過,想要更多詳細展示資訊的朋友可以去部落客的B站影片中查看,在下面的章節中將介紹如何實現以上展示的功能。


2. 車輛數據集

2.1 BDD 100k數據集

    車輛檢測的數據集目前有很多,常見的大型開源數據集當屬BDD 100K十分好用了,作為自動駕駛常用大型多樣化數據集,其標註超過100,000張影像,類別包含公共汽車,行人,自行車,卡車,小汽車,火車和騎手等,用於目標檢測、全幀分割等。該數據集的截圖如下:

功能演示動圖

    若要下載該數據集,可訪問它的官網地址下載,但官網中國的下載速度較慢,這裡已將其整理至百度網盤,需要下載的朋友也可通過部落客的博文《深度學習常見數據集介紹與下載》獲取下載鏈接。下載後的文件目錄如下:

功能演示動圖

    這個數據集確實很大(約10G),訓練的時間實在太長了,因此這個項目裡面不使用全部的數據,而是選擇其中的驗證集「bdd100k_val」文件夾下的文件用於訓練。要使用全部數據集的朋友可將程式中的路徑修改為完整數據集文件夾。

    為了使得該數據集能夠方便用MATLAB處理,從原數據集的標註文件「bdd100k_labels_images_val.json」文件中抽取了小汽車的類別,並重新寫入到mat文件中。篩選和處理部分圖片後,標註文件的資訊包括圖片路徑和標註框的坐標,其數據文件的資訊如下:

功能演示動圖

2.2 自定義數據集

    若要使用自行定義的數據集可按照以上的格式進行處理,通過腳本將標註文件保存為mat格式,如下圖所示為自定義的數據集的圖片文件截圖和標註文件:

功能演示動圖
功能演示動圖

    這兩個數據集都已放在文件夾中,後者只有幾百張圖片,因此對於想要學習和調試程式碼的朋友會很方便。如果不是特別注重準確率,建議使用第二個數據集,在訓練和測試的時候速度會快很多,最後的結果其實也還可以,不妨一試。


3. 搭建並訓練網路

3.1 載入數據集

    首先載入準備好的數據集,查看並顯示數據資訊。其次,對於圖片數據集需要為訓練器指定好每張圖片的絕對路徑,以方便讀取:

clear
clc

doTraining = true; % 是否進行訓練

% 解壓數據
% data = load('./data/carDatasetGroundTruth.mat');
% vehicleDataset = data.carDataset; % table型,包含文件路徑和groundTruth
data = load('./data/vehicleDatasetGroundTruth.mat');
vehicleDataset = data.vehicleDataset; % table型,包含文件路徑和groundTruth

% 添加絕對路徑至vehicleDataset中
vehicleDataset.imageFilename = fullfile([pwd, '/data/'],vehicleDataset.imageFilename);

% 顯示數據集中的一個影像,以了解它包含的影像的類型。
vehicleDataset(1:4,:) % 顯示部分數據情況

    以上程式碼首先載入了標註文件,然後通過fullfile函數將當前文件夾位置添加到圖片路徑中,運行可以查看到部分標註資訊如下:

ans =
  4×2 table
                                   imageFilename                                     vehicle   
    ___________________________________________________________________________    ____________
    {'E:\Works\code\VehicleDetection\train\data\vehicleImages\image_00001.jpg'}    {1×4 double}
    {'E:\Works\code\VehicleDetection\train\data\vehicleImages\image_00002.jpg'}    {1×4 double}
    {'E:\Works\code\VehicleDetection\train\data\vehicleImages\image_00003.jpg'}    {1×4 double}
    {'E:\Works\code\VehicleDetection\train\data\vehicleImages\image_00004.jpg'}    {1×4 double}

    將數據集分成兩部分:一個是用於訓練檢測器的訓練集,一個是用於評估檢測器的測試集,這裡選擇70%的數據進行訓練,其餘數據用於評估。該部分程式碼如下:

% 將數據集分成兩部分:一個是用於訓練檢測器的訓練集,一個是用於評估檢測器的測試集。
% 選擇70%的數據進行訓練,其餘數據用於評估。
rng(0); % 控制隨機數生成
shuffledIndices = randperm(height(vehicleDataset));
idx = floor(0.7 * length(shuffledIndices) );
trainingDataTbl = vehicleDataset(shuffledIndices(1:idx),:);
testDataTbl = vehicleDataset(shuffledIndices(idx+1:end),:);

    將劃分出的訓練和驗證數據集數據和標籤進行轉存,實現程式碼如下:

% 保存數據和標籤
imdsTrain = imageDatastore(trainingDataTbl{:,'imageFilename'}); % 路徑
bldsTrain = boxLabelDatastore(trainingDataTbl(:,'vehicle')); % 真實框和類別

imdsTest = imageDatastore(testDataTbl{:,'imageFilename'});
bldsTest = boxLabelDatastore(testDataTbl(:,'vehicle'));

    聯合文件路徑和真實框,整理訓練和測試集,這部分實現程式碼如下:

% 整理訓練測試集
trainingData = combine(imdsTrain,bldsTrain); % 聯合文件路徑和真實框
testData = combine(imdsTest,bldsTest);

    為了幫助了解標註資訊的使用,可讀取trainingData中的圖片數據及真實框,通過insertShape函數在影像中進行標註並顯示:

% 顯示數據
data = read(trainingData); % data包括圖片數據、真實框坐標、類別
I = data{1};
bbox = data{2};
annotatedImage = insertShape(I,'Rectangle',bbox); % 在數據矩陣中標出真實框
annotatedImage = imresize(annotatedImage,2);
figure
imshow(annotatedImage) % 顯示影像

顯示標註影像如下圖所示:

功能演示動圖

3.2 創建YOLO目標檢測器

    搭建YOLO v2目標檢測網路:YOLO v2由特徵提取網路和檢測網路兩個子網路組成。特徵提取網路通常是預訓練的CNN,這裡特徵提取網路使用的是ResNet-50,當然還可以使用其他經過預訓練的網路,例如MobileNet v2ResNet-18,一般根據應用場景和問題的複雜程度選擇合適的網路。與特徵提取網路相比,檢測網路是一個小的CNN,它由一些卷積層和YOLO v2特有的層組成。MATLAB中提供了yolov2Layers函數,其中給定了預訓練的ResNet-50特徵提取網路,可使用該功能自動創建YOLO v2對象檢測網路。

    yolov2Layers要求指定幾個輸入來參數化YOLO v2網路,詳細使用方法可參考其官方文檔,其參數主要有:

  • 網路輸入大小
  • 錨框
  • 特徵提取網路

    在目標檢測中網路的輸入尺寸一定程度上會影響檢測結果,因此需要評估網路輸入大小和數據的類別數選定。在選擇網路輸入大小時,應先考慮網路本身所需的最小尺寸、訓練影像的大小以及在選定大小下處理數據所產生的計算量。一般情況下,傾向於選擇一個接近於訓練影像大小且大於網路所需輸入大小的網路輸入,這裡為了減少運行程式的計算成本,指定網路輸入大小為[224 224 3](運行網路所需的最小尺寸)。

% 創建yolo網路
inputSize = [448 448 3];
numClasses = width(vehicleDataset)-1; % 通過table的列數計算類別數

    開始訓練之前需要估算錨框,這要考慮影像的調整大小,調整訓練數據的大小以估計錨框。好在MATLAB中提供了estimateAnchorBoxes函數,根據訓練數據中對象的大小來估計錨框。根據transform函數預處理的訓練數據,然後確定錨框個數並估計錨框。使用內置的函數preprocessData將訓練影像數據調整為網路規定的輸入大小。

% 用於評估錨框個數
trainingDataForEstimation = transform(trainingData,@(data)preprocessData(data,inputSize));
numAnchors = 7;
[anchorBoxes, meanIoU] = estimateAnchorBoxes(trainingDataForEstimation, numAnchors)

輸出結果如下:

inputSize = [448 448 3];
anchorBoxes =
    14    10
    34    25
   226   176
   218   114
   124    75
   132   122
    65    53
meanIoU =
    0.6960

    設置特徵提取層網路為resnet50,選擇『activation_40_relu』作為特徵提取層。該特徵提取層輸出的特徵圖經過16倍下取樣,這樣的下取樣量算是空間解析度與所提取特徵強度之間的一個折中,因為經過網路提取的特徵可能會在網路上顯示出更強的影像特徵。一般地,空間解析度的成本以及選擇最佳特徵提取層需要依據經驗分析。搭建網路的程式碼如下:

% 特徵提取層採用resnet50
featureExtractionNetwork = resnet50;

featureLayer = 'activation_40_relu';

% 設置yolo網路
lgraph = yolov2Layers(inputSize,numClasses,anchorBoxes,featureExtractionNetwork,featureLayer);

3.3 數據增強

    數據擴充通過在訓練過程中隨機轉換原始數據來提高網路訓練的準確性。通過使用數據增強,我們可以大大擴充訓練集的大小,而無需增加實際標記的訓練樣本的數量。可使用transform通過隨機水平翻轉影像和關聯的框標籤來增強訓練數據。值得注意的是,理想情況下測試和驗證數據應儘可能代表原始數據,未作修改的數據可以較好地評估模型,因此數據擴充不適用於測試和驗證數據。進行數據增強的程式碼如下:

% 進行數據增強
augmentedTrainingData = transform(trainingData,@augmentData);

% 可視化增強後的圖片
augmentedData = cell(4,1);
for k = 1:4
    data = read(augmentedTrainingData);
    augmentedData{k} = insertShape(data{1},'Rectangle',data{2});
    reset(augmentedTrainingData);
end
figure
montage(augmentedData,'BorderSize',10)

可視化增強後的圖片如下:

功能演示動圖

    預處理訓練數據:對增強後的訓練數據和驗證數據進行預處理,準備進行訓練。然後讀取預處理的訓練數據,這裡顯示一張處理後的影像並標註邊界框,幫助我們瞧一下餵給訓練器的是何方神聖:

% 對增強數據進行預處理
preprocessedTrainingData = transform(augmentedTrainingData,@(data)preprocessData(data,inputSize));

data = read(preprocessedTrainingData);

% 顯示一下
I = data{1};
bbox = data{2};
annotatedImage = insertShape(I,'Rectangle',bbox);
annotatedImage = imresize(annotatedImage,2);
figure
imshow(annotatedImage)

顯示影像如下:

功能演示動圖

3.4 訓練目標檢測網路

    訓練目標檢測器:這裡可以使用trainingOptions容器指定網路的訓練參數,設置『ValidationData』作為預處理的驗證數據;設置『CheckpointPath』為一個臨時位置,這樣能夠保證在訓練過程中及時保存訓練的結果,如果培訓因電源中斷或系統故障而中斷,則可以從保存的檢查點恢復訓練。訓練部分的程式碼如下:

% 訓練參數
options = trainingOptions('sgdm', ...
        'MiniBatchSize', 100, ....
        'InitialLearnRate',1e-3, ...
        'MaxEpochs',30,...
        'CheckpointPath', tempdir, ...
        'Shuffle','never');
    
if doTraining       
    % 訓練YOLOv2檢測器
    [detector,info] = trainYOLOv2ObjectDetector(preprocessedTrainingData,lgraph,options);
else
    % 載入預訓練模型
    pretrained = load('yolov2ResNet50.mat');
    detector = pretrained.detector;
end

    以上程式碼設置了doTraining決定是否執行訓練,當該值為true時開始進行訓練,反之則開始進行測試評估。接下來測試訓練好的模型並顯示測試結果:

% 測試訓練好的模型並顯示
I = imread(testDataTbl.imageFilename{4});
I = imresize(I,inputSize(1:2));
[bboxes,scores] = detect(detector,I);

I = insertObjectAnnotation(I,'rectangle',bboxes,scores);
figure
imshow(I)

顯示檢測結果如下:

功能演示動圖

3.5 評估網路性能

    利用測試集對檢測器進行評估:對於訓練好的目標檢測器有必要在大量影像上進行評估以測試其性能。MATLAB中的Computer Vision Toolbox提供了目標檢測器的評估功能,可以測量一些通用指標,例如平均精度(evaluateDetectionPrecision)和對數平均未命中率(evaluateDetectionMissRate)。在本項目中,我們使用平均精度來評估性能,平均精度中包含了檢測器做出正確分類的能力(精度)和檢測器找到所有相關目標的能力(召回率)。我們將測試數據進行和訓練數據相同的預處理操作,最終用來評估檢測器,這部分程式碼如下:

% 預處理測試集
preprocessedTestData = transform(testData,@(data)preprocessData(data,inputSize));
% 對測試集數據進行測試
detectionResults = detect(detector, preprocessedTestData);
% 評估準確率
[ap,recall,precision] = evaluateDetectionPrecision(detectionResults, preprocessedTestData);

figure
plot(recall,precision)
xlabel('Recall')
ylabel('Precision')
grid on
title(sprintf('Average Precision = %.2f',ap))

    精度/召回率(PR)曲線突出顯示了在不同召回水平下檢測器的精確度,最理想的情況是每處的精度均為1。要想提高平均精度,可以使用更多的訓練數據來提高訓練效果,但這也需要更多的訓練時間。這裡使用的是一個數據量較小的數據集,通過以上程式碼繪製的PR曲線如下圖所示:

功能演示動圖

    作為一個演示項目以上的平均精度還算可以了,可以提升的地方首當是訓練數據量了,因為只選取了一部分數據這使得模型的泛化性能不高,對於擬合效果也沒有作太多的優化,建議大家多做調整優化了。另外,前面程式碼中涉及到的調用函數這裡列出一下:。

% 影像預處理
function data = preprocessData(data,targetSize)
% 調整圖片和Bbox大小至targetSize
scale = targetSize(1:2)./size(data{1},[1 2]);
data{1} = imresize(data{1},targetSize(1:2));
% disp(data{2})
data{2} = bboxresize(data{2},scale);
end
% 影像增強
function B = augmentData(A)
% 應用隨機水平翻轉和隨機X/Y縮放影像;
% 如果重疊大於0.25,則在邊界外縮放的框將被裁減;
% 變換影像顏色
B = cell(size(A));

I = A{1};
sz = size(I);
if numel(sz)==3 && sz(3) == 3
    I = jitterColorHSV(I,...
        'Contrast',0.2,...
        'Hue',0,...
        'Saturation',0.1,...
        'Brightness',0.2);
end

% 隨機翻轉和縮放影像
tform = randomAffine2d('XReflection',true,'Scale',[1 1.1]);
rout = affineOutputView(sz,tform,'BoundsStyle','CenterOutput');
B{1} = imwarp(I,tform,'OutputView',rout);

% 對錨框進行相同的變換
[B{2},indices] = bboxwarp(A{2},tform,rout,'OverlapThreshold',0.25);
B{3} = A{3}(indices);

% 當框的數據不存在時返回原始數據
if isempty(indices)
    B = A;
end
end

下載鏈接

    若您想獲得博文中涉及的實現完整全部程式文件(包括數據集,m, UI文件等,如下圖),這裡已打包上傳至部落客的麵包多平台和CSDN下載資源。本資源已上傳至麵包多網站和CSDN下載資源頻道,可以點擊以下鏈接獲取,已將所有涉及的文件同時打包到裡面,點擊即可運行,完整文件截圖如下:

功能演示動圖

說明:本資源已經過調試通過,下載後可通過MATLAB R2020b運行;另外本程式也通過打包APP應用文件,可雙擊carDetector_UI.mlappinstall文件導入應用,可直接運行所有功能;因為涉及MATLAB部分內置功能,為保證完美運行,請使用MATLAB R2020b及以上版本運行。➷➷➷

完整資源下載鏈接1//mianbaoduo.com/o/bread/YZaal55t

註:以上鏈接為部落客的下載鏈接,CSDN下載資源頻道下載鏈接稍後上傳。部落客最新發布的博文:實時車輛行人多目標檢測與跟蹤系統-上篇(UI介面清新版,Python程式碼)提供了車輛行人檢測與跟蹤的Python版本,介面與效果更加優良,歡迎嘗鮮!

程式碼使用介紹及演示影片鏈接://www.bilibili.com/video/BV1No4y197rW/


結束語

    由於部落客能力有限,博文中提及的方法即使經過試驗,也難免會有疏漏之處。希望您能熱心指出其中的錯誤,以便下次修改時能以一個更完美更嚴謹的樣子,呈現在大家面前。同時如果有更好的實現方法也請您不吝賜教。如果本博文反響較好,其介面部分也將在下篇博文中介紹,所有涉及的GUI介面程式也會作細緻講解,敬請期待!