メインコンテンツ

セマンティック セグメンテーションのためのグラウンド トゥルースのラベル付けの自動化

この例では、事前学習済みのセマンティック セグメンテーション アルゴリズムを使用してイメージ内の空と道路をセグメント化し、このアルゴリズムを使用してグラウンド トゥルース ラベラー (Automated Driving Toolbox)アプリでのグラウンド トゥルースのラベル付けを自動化する方法を説明します。

グラウンド トゥルース ラベラー アプリ

自動運転アルゴリズムを開発し、そのパフォーマンスを評価するには、良好なグラウンド トゥルース データが欠かせません。しかし、注釈付きの走行データから成る多様で高品質なセットを作成して維持するには、多大な労力が必要です。グラウンド トゥルース ラベラー (Automated Driving Toolbox)アプリを使用すると、このプロセスを簡単かつ効率的に行うことができます。このアプリには、四角形、ライン、またはピクセル ラベルとしてオブジェクトに注釈を付ける機能があります。ピクセルのラベル付けは、イメージ内の各ピクセルにクラスまたはカテゴリを割り当てるプロセスであり、これを使用してピクセル レベルのセグメンテーション アルゴリズムに学習させることができます。アプリを使用してすべてのデータに手動でラベルを付けることはできますが、特にピクセルのラベル付けの場合、このプロセスにはかなりの時間とリソースが必要です。アプリでは、代替方法として、ラベル付けプロセスを拡張および自動化するアルゴリズムを組み込むためのフレームワークも利用できます。作成したアルゴリズムを使用してデータ セット全体に自動的にラベルを付けてから、より効率的で短い手動の検証手順で作業を終えることができます。オートメーション ステップの結果を編集して、アルゴリズムが対応しきれなかった難題に対応することもできます。

この例では、次の作業を行います。

  • 事前学習済みのセグメンテーション アルゴリズムを使用して、'道路' および '空' というカテゴリに属するピクセルをセグメント化します。

  • グラウンド トゥルース ラベラー アプリで使用できるオートメーション アルゴリズムを作成して、道路と空のピクセルに自動的にラベルを付けます。

このグラウンド トゥルース データを使用して、新しいセマンティック セグメンテーション ネットワークに学習させたり、既存のネットワークに再学習させたりできます。

道路と空の検出アルゴリズムの作成

まず、イメージ内の道路と空のピクセルをセグメント化するセマンティック セグメンテーション アルゴリズムを作成します。深層学習を使用したセマンティック セグメンテーションの例では、セマンティック セグメンテーション用の深層学習ネットワークに学習させる方法について説明しています。このネットワークには、'道路' と '空' を含む 11 個のクラスのセマンティック ラベルを予測するように学習させています。これらのネットワークのパフォーマンスは、それらがどれだけ一般化できるかによって異なります。学習中に遭遇しなかった状況にネットワークを適用した場合、適切な結果が得られない可能性があります。カスタム学習データを学習プロセスに反復的に導入することで、同様のデータ セットにおけるネットワークのパフォーマンスを向上させることができます。

ネットワークをダウンロードします。このネットワークは Cambridge 大学の CamVid データセット [1] で事前学習済みです。

pretrainedURL = "https://ssd.mathworks.com/supportfiles/vision/data/deeplabv3plusResnet18CamVid_v2.zip";
pretrainedFolder = fullfile(tempdir,"pretrainedNetwork");
pretrainedNetworkZip = fullfile(pretrainedFolder,"deeplabv3plusResnet18CamVid_v2.zip"); 
if ~exist(pretrainedNetworkZip,'file')
    mkdir(pretrainedFolder);
    disp("Downloading pretrained network (58 MB)...");
    websave(pretrainedNetworkZip,pretrainedURL);
end
unzip(pretrainedNetworkZip, pretrainedFolder)

事前学習済みのネットワークを読み込みます。

pretrainedNetwork = fullfile(pretrainedFolder,"deeplabv3plusResnet18CamVid_v2.mat");

% Load the semantic segmentation network
data = load(pretrainedNetwork);

分類用にこのネットワークに学習させたクラスを設定します。

classes = getClassNames()
classes = 11×1 string
    "Sky"
    "Building"
    "Pole"
    "Road"
    "Pavement"
    "Tree"
    "SignSymbol"
    "Fence"
    "Car"
    "Pedestrian"
    "Bicyclist"

イメージをセグメント化して表示します。

% Load a test image from drivingdata
roadSequenceData = fullfile(toolboxdir('driving'), 'core','drivingdata', 'roadSequence');
I = imread(fullfile(roadSequenceData, 'f00001.png'));
inputSize = data.net.Layers(1).InputSize;
I = imresize(I,inputSize(1:2));

% Run the network on the image
automatedLabels = semanticseg(I, data.net, Classes=classes);

% Display the labels overlaid on the image, choosing relevant categories
figure
imshow(labeloverlay(I, automatedLabels, IncludedLabels=["Sky", "Road"]));

Figure contains an axes object. The axes object contains an object of type image.

青いオーバーレイは '空' カテゴリ、緑のオーバーレイは '道路' カテゴリを示します。

グラウンド トゥルース ラベラーへのピクセル セグメンテーション アルゴリズムの統合

抽象基底クラスvision.labeler.AutomationAlgorithmから継承するクラスを作成して、このセマンティック セグメンテーション アルゴリズムをアプリのオートメーション ワークフローに組み込みます。この基底クラスは、アルゴリズムの構成と実行のためにアプリが使用する API を定義するものです。グラウンド トゥルース ラベラー アプリは、最初のオートメーション クラス テンプレートを取得するための便利な方法を提供します。詳細については、ラベル付け用オートメーション アルゴリズムの作成を参照してください。RoadAndSkySegmentation クラスはこのテンプレートに基づいており、ピクセル ラベル セグメンテーション用のすぐに使用できるオートメーション クラスを提供します。

RoadAndSkySegmentation クラスの最初のプロパティ セットでは、アルゴリズムの名前を指定し、アルゴリズムの簡単な説明を提供し、使用方法を示します。

    properties(Constant)
        % Name
        %   Character vector specifying name of algorithm.
        Name = 'RoadAndSkySegmentation'

        % Description
        %   Character vector specifying short description of algorithm.
        Description = 'This algorithm uses semanticseg with a pretrained network to annotate roads and sky'

        % UserDirections
        %   Cell array of character vectors specifying directions for
        %   algorithm users to follow in order to use algorithm.
        UserDirections = {...
            ['Automation algorithms are a way to automate manual labeling ' ...
            'tasks. This AutomationAlgorithm automatically creates pixel ', ...
            'labels for road and sky.'], ...
            ['Review and Modify: Review automated labels over the interval ', ...
            'using playback controls. Modify/delete/add ROIs that were not ' ...
            'satisfactorily automated at this stage. If the results are ' ...
            'satisfactory, click Accept to accept the automated labels.'], ...
            ['Accept/Cancel: If results of automation are satisfactory, ' ...
            'click Accept to accept all automated labels and return to ' ...
            'manual labeling. If results of automation are not ' ...
            'satisfactory, click Cancel to return to manual labeling ' ...
            'without saving automated labels.']};

        % ClassNames
        %   String array of all the classes the pretrained network has been
        %   trained on.
        ClassNames = [
            "Sky"
            "Building"
            "Pole"
            "Road"
            "Pavement"
            "Tree"
            "SignSymbol"
            "Fence"
            "Car"
            "Pedestrian"
            "Bicyclist"
            ]
    end

RoadAndSkySegmentation クラスの次のセクションでは、コア アルゴリズムに必要なカスタム プロパティを指定します。PretrainedNetwork プロパティは、事前学習済みのネットワークを保持します。AllCategories プロパティは、すべてのカテゴリの名前を保持します。

    properties
        % PretrainedNetwork saves the SeriesNetwork object that does the semantic
        % segmentation.
        PretrainedNetwork

        % Categories holds the default 'background', 'road', and 'sky'
        % categorical types.
        AllCategories = {'background'};

        % Store names for 'road' and 'sky'.
        RoadName
        SkyName
    end

RoadAndSkySegmentation で定義された最初のメソッドである checkLabelDefinition では、タイプ PixelLabel のラベルのみがオートメーションに対して有効になっていることを確認します。PixelLabel は、セマンティック セグメンテーションに必要な唯一のタイプです。

    function TF = checkLabelDefinition(~, labelDef)
        isValid = false;

        if (strcmpi(labelDef.Name, 'road') && labelDef.Type == labelType.PixelLabel)
            isValid = true;
            algObj.RoadName = labelDef.Name;
            algObj.AllCategories{end+1} = labelDef.Name;
        elseif (strcmpi(labelDef.Name, 'sky') && labelDef.Type == labelType.PixelLabel)
            isValid = true;
            algObj.SkyName = labelDef.Name;
            algObj.AllCategories{end+1} = labelDef.Name;
        elseif(labelDef.Type == labelType.PixelLabel)
            isValid = true;
        end
    end

次の関数セットは、アルゴリズムの実行を制御します。vision.labeler.AutomationAlgorithm クラスには、オートメーションを簡単にセットアップして実行するための 'initialize''run''terminate' などのメソッドを含むインターフェイスが含まれています。関数 initialize は、アプリ内の既存のラベルに基づいてアルゴリズムの初期状態を設定します。RoadAndSkySegmentation クラスでは、関数 initialize をカスタマイズして、事前学習済みのセマンティック セグメンテーション ネットワークを tempdir から読み込み、PretrainedNetwork プロパティに保存します。

    function initialize(algObj, ~, ~)
        % Point to tempdir where pretrainedNetwork was downloaded.
        pretrainedFolder = fullfile(tempdir,'pretrainedNetwork');
        pretrainedNetwork = fullfile(pretrainedFolder,'deeplabv3plusResnet18CamVid_v2.mat'); 
        data = load(pretrainedNetwork);
            
        % Store the network in the 'net' property of this object.
        algObj.PretrainedNetwork = data.net;
    end

次に、関数 run は、このオートメーション クラスのセマンティック セグメンテーションのコア アルゴリズムを定義します。run はビデオ フレームごとに呼び出され、オートメーション クラスによってラベルのセットが返される必要があります。RoadAndSkySegmentation の関数 run には、"道路" と "空" に対応するピクセル ラベルの categorical 行列を作成するために既に紹介したロジックが含まれています。説明のためにここでは 2 つに制限していますが、ネットワークに学習させる任意のカテゴリにこれを拡張できます。

    function autoLabels = run(algObj, I)
        % Resize image to expected network size
        img = imresize(I,algObj.PretrainedNetwork.Layers(1).InputSize(1:2));

        % Setup categorical matrix with categories including road and
        % sky
        autoLabels = categorical(zeros(size(I,1), size(I,2)),0:2,algObj.AllCategories,Ordinal=true);
        
        pixelCat = semanticseg(img,algObj.PretrainedNetwork,Classes=algObj.ClassNames);
        
        % Resize the categorical matrix back to the size of the
        % original input image.
        pixelCatResized = imresize(pixelCat,size(I,1:2));
        if ~isempty(pixelCatResized)
            % Add the selected label at the bounding box position(s)
            autoLabels(pixelCatResized == "Road") = algObj.RoadName;
            autoLabels(pixelCatResized == "Sky") = algObj.SkyName;
        end

    end

このアルゴリズムはクリーンアップを必要としないため、関数 terminate は空です。

アプリでのピクセル セグメンテーション オートメーション クラスの使用

前のセクションで説明したプロパティとメソッドは、RoadAndSkySegmentation オートメーション アルゴリズム クラス ファイルに実装されています。アプリでこのクラスを使用するには次のようにします。

  • 必要なフォルダー構造 +vision/+labeler を現在のフォルダーの下に作成し、オートメーション クラスをそこにコピーします。

    mkdir('+vision/+labeler');
    copyfile('RoadAndSkySegmentation.m','+vision/+labeler');
  • ラベル付けを行うためのカスタム データを使用して groundTruthLabeler アプリを開きます。説明用に、caltech_cordova1.avi のビデオを開きます。

    groundTruthLabeler caltech_cordova1.avi
  • アプリのツールストリップの [グラウンド トゥルース ラベラー] タブにある [ラベルの定義] セクションで [ラベルの追加] をクリックし、ドロップ ダウンから [Pixel] を選択します。RoadSky という名前の 2 つのピクセル ラベルを定義します。各ラベルの色を選択できます。[OK] をクリックします。

SemanticSegAlgorithmDefineLabel.png

  • [アルゴリズム]、[アルゴリズムの選択]、[リストの更新] をクリックします。

SemanticSegAlgorithmSelectAlgorithm.png

  • [アルゴリズム]、[RoadAndSkySegmentation] をクリックします。このオプションが表示されない場合は、+vision/+labeler というフォルダーが現在の作業フォルダーにあり、RoadAndSkySegmentation.m という名前のファイルがそこに含まれていることを確認します。

  • [自動化] をクリックします。新しいパネルが開き、アルゴリズムの使用方法が表示されます。

  • [実行] をクリックします。作成されたアルゴリズムがビデオの各フレームで実行され、"道路" と "空" のカテゴリをセグメント化します。実行が完了したら、スライダーまたは矢印キーを使用してビデオをスクロールし、オートメーション アルゴリズムの結果を確認します。

SemanticSegAlgorithmAutoResult.png

  • 自動化により空のラベル付けはかなりうまく行われますが、自車両の一部が明らかに "道路" としてマークされています。これらの結果は、ネットワークが以前にそのようなデータを学習したことがないことを示しています。このワークフローでは、これらの結果を手動で修正できるため、学習とラベル付けの反復プロセス ("アクティブ ラーニング" または "ヒューマン イン ザ ループ" とも呼ばれる) を使用して、カスタム データ セットのネットワークの精度をさらに向上させることができます。[ピクセルのラベル付け] タブのブラシ ツールを使用し、ピクセル注釈を追加または削除して、結果を手動で微調整できます。[ピクセルのラベル付け] タブでは、塗りつぶしやスマート ポリゴンなどの他のツールも必要に応じて使用できます。

SemanticSegAlgorithmFinalResult.png

  • ビデオ全体のピクセル ラベル カテゴリが満足のいく状態になったら、[確定] をクリックします。

ビデオのピクセルのラベル付けの自動化が完了しました。他の対象オブジェクトのラベル付けの実行、セッションの保存、このラベル付けの実行結果のエクスポートができるようになりました。

まとめ

この例では、事前学習済みのセマンティック セグメンテーション ネットワークを使用し、グラウンド トゥルース ラベラー アプリで AutomationAlgorithm インターフェイスを使用して道路と空のピクセルのラベル付けを高速化する方法を示しました。

サポート関数

function classes = getClassNames()
classes = [
    "Sky"
    "Building"
    "Pole"
    "Road"
    "Pavement"
    "Tree"
    "SignSymbol"
    "Fence"
    "Car"
    "Pedestrian"
    "Bicyclist"
    ];
end

参考文献

[1] Brostow, G. J., J. Fauqueur, and R. Cipolla. "Semantic object classes in video: A high-definition ground truth database." Pattern Recognition Letters. Vol. 30, Issue 2, 2009, pp 88-97.