Main Content

車線検出と車両検出を実行する深層学習 Simulink モデルのコード生成

この例では、畳み込みニューラル ネットワーク (CNN) を使用して車線検出と車両検出を実行する Simulink® モデルから C++ コードを生成する方法を示します。この例では、交通ビデオのフレームを入力として受け取り、自車の左右の車線に対応する 2 つの車線境界線を出力し、フレーム内の車両を検出します。この例では、Computer Vision Toolbox™ の "YOLO v2 深層学習を使用したオブジェクトの検出" の例から、事前学習済みの車線検出ネットワークと事前学習済みの車両検出ネットワークを使用します。詳細については、YOLO v2 深層学習を使用したオブジェクトの検出 (Computer Vision Toolbox)を参照してください。

この例では次の概念を示します。

  • Simulink で車線検出アプリケーションをモデル化します。最初に、交通ビデオのサイズを 227×227×3 に変更し、定数係数 255 で乗算して処理します。次に、Deep Learning Toolbox™ から Predict ブロックに読み込んだ事前学習済みのネットワークを使用して交通ビデオを処理します。最後に、左右の車線境界線が検出されると、車線境界線の軌跡をモデル化するための放物線の係数が得られます。

  • 事前学習済みの YOLO v2 検出器を使用して交通ビデオを処理することで、Simulink で車両検出アプリケーションをモデル化します。このネットワークは、ビデオ内の車両を検出し、それらの車両の境界ボックスの座標とその信頼度スコアを出力します。

  • コードを生成するためにモデルを設定します。

前提条件

  • Intel Math Kernel Library for Deep Neural Networks (MKL-DNN)。

  • MKL-DNN ライブラリをサポートするプロセッサのリストについては、MKLDNN CPU Support を参照してください。

  • Deep Learning Toolbox™ (DAGNetwork オブジェクトを使用するため)。

  • Computer Vision Toolbox™ (ビデオ I/O 操作用)。

アルゴリズム ワークフロー

Simulink モデルのアルゴリズム ワークフローのブロック線図を次に示します。

事前学習済みの車線検出ネットワークと車両検出ネットワークの取得

この例では、事前学習済みのネットワークを含む trainedLaneNetyolov2ResNet50VehicleExample の MAT ファイルを使用します。それぞれのファイルのサイズは約 143 MB と約 98 MB です。ファイルをダウンロードします。

lanenetFile = matlab.internal.examples.downloadSupportFile('gpucoder/cnn_models/lane_detection','trainedLaneNet.mat');
vehiclenetFile = matlab.internal.examples.downloadSupportFile('vision/data','yolov2ResNet50VehicleExample.mat');

テスト用の交通ビデオのダウンロード

モデルをテストするために、この例では Caltech の車線データ セットを使用します。ファイルのサイズは約 16 MB です。このファイルをダウンロードします。

mediaFile = matlab.internal.examples.downloadSupportFile('gpucoder/media','caltech_washington1.avi');

車線検出と車両検出の Simulink モデル

次のブロック線図は、交通ビデオで車線検出と車両検出を実行するための Simulink モデルを示しています。モデルを実行すると、車線と車両に注釈を付けた交通ビデオが Video Viewer ブロックで表示されます。

model='laneAndVehicleDetection';
open_system(model);

Simulink モデルの Predict ブロックと Detector ブロックで、ダウンロードしたネットワーク モデルのファイル パスを設定します。

set_param('laneAndVehicleDetection/Lane Detection','NetworkFilePath',lanenetFile)
set_param('laneAndVehicleDetection/Vehicle Detector','DetectorFilePath',vehiclenetFile)

Simulink モデルに読み込むテスト用ビデオの場所を設定します。

set_param('laneAndVehicleDetection/Traffic Video','inputFileName',mediaFile)

車線検出

Predict ブロックは、事前学習済みの車線検出ネットワークを trainedLaneNet.mat ファイルから読み込みます。このネットワークは、イメージを入力として受け取り、自車の左右の車線に対応する 2 つの車線境界線を出力します。各車線境界線は、次の放物線方程式によって表されます。

$y = ax^2+bx+c$

ここで、y は横方向のオフセット、x は車両からの縦方向の距離です。このネットワークは、車線ごとに 3 つのパラメーター a、b、c を出力します。LaneDetectionCoordinates MATLAB Function ブロックは、関数 lane_detection_coordinates を定義します。この関数は、Predict ブロックからの出力を受け取り、3 つのパラメーター laneFoundltPtsrtPts を出力します。このブロックでは、しきい値処理を使用して、左右両方の車線境界線がどちらも検出されたかどうかを判定します。それらが検出されると、laneFound が true に設定され、境界線の軌跡が計算されて ltPtsrtPts に格納されます。

type lane_detection_coordinates
function [laneFound,ltPts,rtPts] = lane_detection_coordinates(laneNetOut)

% Copyright 2020 The MathWorks, Inc.

persistent laneCoeffMeans;
if isempty(laneCoeffMeans)
    laneCoeffMeans = [-0.0002    0.0002    1.4740   -0.0002    0.0045   -1.3787];
end

persistent laneCoeffStds;
if isempty(laneCoeffStds)
    laneCoeffStds = [0.0030    0.0766    0.6313    0.0026    0.0736    0.9846];
end

params = laneNetOut .* laneCoeffStds + laneCoeffMeans;

isRightLaneFound = abs(params(6)) > 0.5; %c should be more than 0.5 for it to be a right lane
isLeftLaneFound =  abs(params(3)) > 0.5;

persistent vehicleXPoints;
if isempty(vehicleXPoints)
    vehicleXPoints = 3:30; %meters, ahead of the sensor
end

ltPts = coder.nullcopy(zeros(28,2,'single'));
rtPts = coder.nullcopy(zeros(28,2,'single'));

if isRightLaneFound && isLeftLaneFound
    rtBoundary = params(4:6);
    rt_y = computeBoundaryModel(rtBoundary, vehicleXPoints);
    ltBoundary = params(1:3);
    lt_y = computeBoundaryModel(ltBoundary, vehicleXPoints);
    
    % Visualize lane boundaries of the ego vehicle
    tform = get_tformToImage;
    % map vehicle to image coordinates
    ltPts =  tform.transformPointsInverse([vehicleXPoints', lt_y']);
    rtPts =  tform.transformPointsInverse([vehicleXPoints', rt_y']);
    laneFound = true;
else
    laneFound = false;
end

end

車両検出

YOLO v2 オブジェクト検出ネットワークは、特徴抽出ネットワークとそれに続く検出ネットワークの 2 つのサブネットワークで構成されます。事前学習済みのネットワークは、特徴抽出に ResNet-50 を使用します。検出サブネットワークは、特徴抽出ネットワークに比べて小さい CNN であり、少数の畳み込み層と YOLO v2 に固有の層で構成されます。Simulink モデルは、Object Detector ブロックを使用して車両検出を実行します。このブロックは、イメージを入力として受け取り、イメージ内の車両の境界ボックス座標を信頼度スコアと共に出力します。

車両の境界ボックスと交通ビデオの車線の軌跡に対する注釈

LaneVehicleAnnotation MATLAB Function ブロックは、関数 lane_vehicle_annotation を定義します。この関数は、車両の境界ボックスに信頼度スコアと共に注釈を付けます。また、laneFound が true の場合は、交通ビデオで ltPtsrtPts に格納された左右の車線境界線にも注釈が付けられます。

type lane_vehicle_annotation
function In = lane_vehicle_annotation(laneFound, ltPts, rtPts, bboxes, scores, In)

% Copyright 2020 The MathWorks, Inc.

if ~isempty(bboxes)
    In = insertObjectAnnotation(In, 'rectangle', bboxes, scores);
end

pts = coder.nullcopy(zeros(28, 4, 'single'));
if laneFound
    prevpt =  [ltPts(1,1) ltPts(1,2)];
    for k = 2:1:28
        pts(k,1:4) = [prevpt ltPts(k,1) ltPts(k,2)];
        prevpt = [ltPts(k,1) ltPts(k,2)];
    end
    In = insertShape(In, 'Line', pts, 'LineWidth', 2);
    prevpt =  [rtPts(1,1) rtPts(1,2)];
    for k = 2:1:28
        pts(k,1:4) = [prevpt rtPts(k,1) rtPts(k,2)];
        prevpt = [rtPts(k,1) rtPts(k,2)];
    end
    In = insertShape(In, 'Line', pts, 'LineWidth', 2);
    In = insertMarker(In, ltPts);
    In = insertMarker(In, rtPts);
end

end

事前学習済みの車線検出ネットワークと車両検出ネットワークの取得

次の関数は、yolov2ResNet50VehicleExample.mat ファイルをダウンロードします。

getVehicleDetectionAndLaneDetectionNetworks()

シミュレーションの実行

[コンフィギュレーション パラメーター] ダイアログ ボックスを開きます。[シミュレーション ターゲット] ペインの [深層学習] グループで、[ターゲット ライブラリ] として MKL-DNN を選択します。

set_param(model,'SimDLTargetLibrary','MKL-DNN');

[インターフェイス] ペインの [深層学習] グループで、[ターゲット ライブラリ] として MKL-DNN を選択します。

set_param(model, 'DLTargetLibrary','MKL-DNN');

車線検出と車両検出のアルゴリズムを検証し、Simulink モデルに読み込まれた交通ビデオの車線の軌跡、車両の境界ボックス、スコアを表示するために、シミュレーションを実行します。

set_param('laneAndVehicleDetection', 'SimulationMode', 'Normal');
sim('laneAndVehicleDetection');

Simulink モデルの生成とビルド

[コード生成] ペインで、[言語] として [C++] を選択します。

set_param(model,'TargetLang','C++');

slbuild コマンドを使用して Simulink モデルを生成およびビルドします。コード ジェネレーターは、現在の作業フォルダーの配下にある laneAndVehicleDetection_grt_rtw ビルド サブフォルダーにファイルを配置します。

currentDir = pwd;
status = evalc("slbuild('laneAndVehicleDetection')");

生成された C++ コード

laneAndVehicleDetection_grt_rtw という名前のサブフォルダーに、Simulink モデル内のそれぞれのブロックとそれらのブロックで実行される特定の操作に対応する C++ 生成コードが格納されます。たとえば、ファイル trainedLaneNet0_0.h には、事前学習済みの車線検出ネットワークを表す属性とメンバー関数を含む C++ クラスが格納されます。

hfile = fullfile(currentDir, 'laneAndVehicleDetection_grt_rtw',...
    'trainedLaneNet0_0.h');
coder.example.extractLines(hfile,'#ifndef RTW_HEADER_trainedLaneNet0_0_h_',...
    '#endif')
#ifndef RTW_HEADER_trainedLaneNet0_0_h_
#define RTW_HEADER_trainedLaneNet0_0_h_
#include "MWOnednnTargetNetworkImpl.hpp"
#include "MWTensorBase.hpp"
#include "MWTensor.hpp"
#include "MWCNNLayer.hpp"
#include "MWInputLayer.hpp"
#include "MWElementwiseAffineLayer.hpp"
#include "MWFusedConvActivationLayer.hpp"
#include "MWNormLayer.hpp"
#include "MWMaxPoolingLayer.hpp"
#include "MWFCLayer.hpp"
#include "MWReLULayer.hpp"
#include "MWOutputLayer.hpp"
#include "MWConvLayer.hpp"
#include "MWYoloExtractionLayer.hpp"
#include "MWSigmoidLayer.hpp"
#include "MWExponentialLayer.hpp"
#include "MWYoloSoftmaxLayer.hpp"
#include "MWConcatenationLayer.hpp"
#include "MWActivationFunctionType.hpp"
#include "MWRNNParameterTypes.hpp"
#include "MWTargetTypes.hpp"
#include "shared_layers_export_macros.hpp"
#include "MWOnednnUtils.hpp"
#include "MWOnednnCustomLayerBase.hpp"
#include "MWOnednnCommonHeaders.hpp"
#include "rtwtypes.h"

class trainedLaneNet0_0
{
 public:
  boolean_T isInitialized;
  boolean_T matlabCodegenIsDeleted;
  trainedLaneNet0_0();
  void setSize();
  void resetState();
  void setup();
  void predict();
  void cleanup();
  real32_T *getLayerOutput(int32_T layerIndex, int32_T portIndex);
  int32_T getLayerOutputSize(int32_T layerIndex, int32_T portIndex);
  real32_T *getInputDataPointer(int32_T index);
  real32_T *getInputDataPointer();
  real32_T *getOutputDataPointer(int32_T index);
  real32_T *getOutputDataPointer();
  int32_T getBatchSize();
  int32_T getOutputSequenceLength(int32_T layerIndex, int32_T portIndex);
  ~trainedLaneNet0_0();
 private:
  int32_T numLayers;
  MWTensorBase *inputTensors;
  MWTensorBase *outputTensors;
  MWCNNLayer *layers[18];
  MWOnednnTarget::MWTargetNetworkImpl *targetImpl;
  void allocate();
  void postsetup();
  void deallocate();
};

同様に、ファイル yolov2ResNet50VehicleExample0_0.h には、事前学習済みの YOLO v2 検出ネットワークを表す C++ クラスが格納されます。

hfile = fullfile(currentDir, 'laneAndVehicleDetection_grt_rtw',...
    'yolov2ResNet50VehicleExample0_0.h');
coder.example.extractLines(hfile,'#ifndef RTW_HEADER_yolov2ResNet50VehicleExample0_0_h_',...
    '#endif')
#ifndef RTW_HEADER_yolov2ResNet50VehicleExample0_0_h_
#define RTW_HEADER_yolov2ResNet50VehicleExample0_0_h_
#include "MWOnednnTargetNetworkImpl.hpp"
#include "MWTensorBase.hpp"
#include "MWTensor.hpp"
#include "MWCNNLayer.hpp"
#include "MWInputLayer.hpp"
#include "MWElementwiseAffineLayer.hpp"
#include "MWFusedConvActivationLayer.hpp"
#include "MWNormLayer.hpp"
#include "MWMaxPoolingLayer.hpp"
#include "MWFCLayer.hpp"
#include "MWReLULayer.hpp"
#include "MWOutputLayer.hpp"
#include "MWConvLayer.hpp"
#include "MWYoloExtractionLayer.hpp"
#include "MWSigmoidLayer.hpp"
#include "MWExponentialLayer.hpp"
#include "MWYoloSoftmaxLayer.hpp"
#include "MWConcatenationLayer.hpp"
#include "MWActivationFunctionType.hpp"
#include "MWRNNParameterTypes.hpp"
#include "MWTargetTypes.hpp"
#include "shared_layers_export_macros.hpp"
#include "MWOnednnUtils.hpp"
#include "MWOnednnCustomLayerBase.hpp"
#include "MWOnednnCommonHeaders.hpp"
#include "rtwtypes.h"

class yolov2ResNet50VehicleExample0_0
{
 public:
  boolean_T isInitialized;
  boolean_T matlabCodegenIsDeleted;
  yolov2ResNet50VehicleExample0_0();
  void setSize();
  void resetState();
  void setup();
  void predict();
  void activations(int32_T layerIdx);
  void cleanup();
  real32_T *getLayerOutput(int32_T layerIndex, int32_T portIndex);
  int32_T getLayerOutputSize(int32_T layerIndex, int32_T portIndex);
  real32_T *getInputDataPointer(int32_T index);
  real32_T *getInputDataPointer();
  real32_T *getOutputDataPointer(int32_T index);
  real32_T *getOutputDataPointer();
  int32_T getBatchSize();
  int32_T getOutputSequenceLength(int32_T layerIndex, int32_T portIndex);
  ~yolov2ResNet50VehicleExample0_0();
 private:
  int32_T numLayers;
  MWTensorBase *inputTensors;
  MWTensorBase *outputTensors;
  MWCNNLayer *layers[57];
  MWOnednnTarget::MWTargetNetworkImpl *targetImpl;
  void allocate();
  void postsetup();
  void deallocate();
};

メモ: [システム ターゲット ファイル] パラメーターが grt.tlc に設定されている場合、[コード生成のみ] モデル コンフィギュレーション パラメーターを選択する必要があります。[システム ターゲット ファイル]ert.tlc に設定すると、[コード生成のみ] パラメーターをクリアできますが、実行可能ファイルを作成するためにメイン プログラム例の生成が必要になります。

クリーンアップ

Simulink モデルを閉じます。

save_system('laneAndVehicleDetection');
close_system('laneAndVehicleDetection');