Main Content

セマンティック セグメンテーションのためのピクセル ラベルの拡張

この例では、セマンティック セグメンテーション ワークフローの一環としてイメージとピクセル ラベルの一般的な種類の拡張を行う方法について説明します。

セマンティック セグメンテーションの学習データは、数値行列で表されるイメージ、および categorical 行列で表されるピクセル ラベルで構成されます。学習データを拡張する場合、イメージおよび関連付けられたピクセル ラベルに対して同一の変換を適用しなければなりません。この例では、3 種類の一般的な変換を示します。

この例では、複数の種類の変換を組み合わせて、データストア内のセマンティック セグメンテーション用学習データに対する拡張の適用を実行する方法を説明します。

拡張した学習データを使用してネットワークに学習させることができます。セマンティック セグメンテーション ネットワークの学習方法を示す例については、深層学習を使用したセマンティック セグメンテーションを参照してください。

この例では、さまざまな種類の拡張の効果を示すため、各変換に同じ入力イメージとピクセル ラベル イメージを使用します。

サンプル イメージを読み取ります。

filenameImage = 'kobi.png';
I = imread(filenameImage);

ピクセル ラベル イメージを読み取ります。イメージには 2 つのクラスがあります。

filenameLabels = 'kobiPixelLabeled.png';
L = imread(filenameLabels);
classes = ["floor","dog"];
ids = [1 2];

ピクセル ラベル イメージを categorical データ型に変換します。

C = categorical(L,ids,classes);

関数 labeloverlay を使用して、ラベルをイメージの上に重ねて表示します。"floor" のラベルが付いたピクセルは青みがかっており、"dog" のラベルが付いたピクセルはシアン調になっています。

B = labeloverlay(I,C);
imshow(B)
title('Original Image and Pixel Labels')

イメージとピクセル ラベルのサイズ変更

関数 imresize を使用することで、数値イメージと categorical イメージのサイズを変更できます。イメージとピクセル ラベル イメージを同じサイズに変更し、ラベルをイメージの上に重ねて表示します。

targetSize = [300 300];
resizedI = imresize(I,targetSize);
resizedC = imresize(C,targetSize);

サイズ変更したイメージの上に、サイズ変更したラベルを重ねて表示します。

B = labeloverlay(resizedI,resizedC);
imshow(B)
title('Resized Image and Pixel Labels')

イメージとピクセル ラベルのトリミング

トリミングは、データのサイズをネットワークの入力サイズに一致させるための一般的な前処理手順です。目的のサイズの出力イメージを作成するには、まず、関数randomWindow2dcenterCropWindow2dを使用して、トリミング ウィンドウのサイズと位置を指定します。イメージ内の目的の内容が確実に含まれるようにトリミング ウィンドウを選択してください。次に、imcrop を使用して、イメージとピクセル ラベル イメージを同じウィンドウにトリミングします。

トリミングした領域の目的のサイズを、[高さ, 幅] の形式の 2 要素のベクトルとして指定します。

targetSize = [300 300];

イメージの中心から、ターゲット サイズでトリミングします。

win = centerCropWindow2d(size(I),targetSize);
croppedI = imcrop(I,win);
croppedC = imcrop(C,win);

トリミングしたイメージの上に、トリミングしたラベルを重ねて表示します。

B = labeloverlay(croppedI,croppedC);
imshow(B)
title('Center Cropped Image and Pixel Labels')

イメージ内のランダムな位置から、ターゲットのサイズにイメージをトリミングします。

win = randomWindow2d(size(I),targetSize);
croppedI = imcrop(I,win);
croppedC = imcrop(C,win);

トリミングしたイメージの上に、トリミングしたラベルを重ねて表示します。

B = labeloverlay(croppedI,croppedC);
imshow(B)
title('Random Cropped Image and Pixel Labels')

イメージとピクセル ラベルのワープ

関数 randomAffine2d は、回転、平行移動、スケーリング (サイズ変更)、反転、せん断の組み合わせからランダムな 2 次元アフィン変換を作成します。imwarp を使用して、イメージとピクセル ラベル イメージに変換を適用します。関数 affineOutputView を使用して、ワープされた出力の空間の範囲と解像度を制御します。

[-50,50] 度の範囲からランダムに選択した角度で、入力イメージとピクセル ラベル イメージを回転させます。

tform = randomAffine2d("Rotation",[-50 50]);

ワープされたイメージとピクセル ラベル イメージの出力表示を作成します。

rout = affineOutputView(size(I),tform);

imwarp を使用して、イメージとピクセル ラベル イメージを回転させます。

rotatedI = imwarp(I,tform,'OutputView',rout);
rotatedC = imwarp(C,tform,'OutputView',rout);

回転させたイメージの上に、回転させたラベルを重ねて表示します。

B = labeloverlay(rotatedI,rotatedC);
imshow(B)
title('Rotated Image and Pixel Labels')

データストア内のセマンティック セグメンテーション用学習データに対する拡張の適用

データストアは、イメージ コレクションの読み取りや拡張に便利です。イメージとピクセル ラベル イメージのデータを格納するデータストアを作成し、一連の演算を使用してデータを拡張します。

イメージとピクセル ラベル イメージのデータを格納するデータストアの作成

サンプル データストアのサイズを増やすために、イメージとピクセル ラベル イメージのファイル名を複製します。

numObservations = 4;
trainImages = repelem({filenameImage},numObservations,1);
trainLabels = repelem({filenameLabels},numObservations,1);

学習用のイメージ ファイルから imageDatastore を作成します。学習用のピクセル ラベル ファイルから pixelLabelDatastore を作成します。このデータストアには、同じデータの複数のコピーが格納されます。

imds = imageDatastore(trainImages);
pxds = pixelLabelDatastore(trainLabels,classes,ids);

イメージ データストアとピクセル ラベル データストアを結合し、イメージとピクセル ラベルのペアを関連付けます。

trainingData = combine(imds,pxds);

結合したデータストアから、最初のイメージとそれに関連付けられたピクセル ラベル イメージを読み取ります。

data = read(trainingData);
I = data{1};
C = data{2};

イメージとピクセル ラベル データを表示します。

B = labeloverlay(I,C);
imshow(B)

データ拡張の適用

関数 transform を使用して、学習データにデータ拡張を適用します。この例では、2 つの別個の拡張を学習データに適用します。

最初の拡張では、イメージの色にジッターを付加した後、イメージとピクセル ラベル イメージのペアに対して、同一のランダム スケーリング、水平方向の反転、および回転を適用します。これらの演算は、この例の終わりにある補助関数 jitterImageColorAndWarp で定義されます。

augmentedTrainingData = transform(trainingData,@jitterImageColorAndWarp);

拡張されたデータをすべて読み取ります。

data = readall(augmentedTrainingData);

拡張されたイメージとピクセル ラベル データを表示します。

rgb = cell(numObservations,1);
for k = 1:numObservations
    I = data{k,1};
    C = data{k,2};
    rgb{k} = labeloverlay(I,C);
end
montage(rgb)

2 番目の拡張では、イメージとピクセル ラベル イメージをターゲット サイズで中央トリミングします。これらの演算は、この例の終わりにある補助関数 centerCropImageAndLabel で定義されます。

targetSize = [800 800];
preprocessedTrainingData = transform(augmentedTrainingData,...
    @(data)centerCropImageAndLabel(data,targetSize));

前処理されたデータをすべて読み取ります。

data = readall(preprocessedTrainingData);

前処理されたイメージとピクセル ラベル データを表示します。

rgb = cell(numObservations,1);
for k = 1:numObservations
    I = data{k,1};
    C = data{k,2};
    rgb{k} = labeloverlay(I,C);
end
montage(rgb)

拡張の補助関数

補助関数 jitterImageColorAndWarp は、イメージ データにランダムなカラー ジッターを適用した後、イメージとピクセル ラベル イメージのデータに同一のアフィン変換を適用します。変換は、[0.8 1.5] の範囲のスケール係数でのスケーリング、水平方向の反転、および [-30, 30] 度の範囲での回転のランダムな組み合わせで構成されます。入力 data と出力 out は 2 要素の cell 配列で、最初の要素がイメージ データ、2 番目の要素がピクセル ラベル イメージ データです。

function out = jitterImageColorAndWarp(data)
% Unpack original data.
I = data{1};
C = data{2};

% Apply random color jitter.
I = jitterColorHSV(I,"Brightness",0.3,"Contrast",0.4,"Saturation",0.2);

% Define random affine transform.
tform = randomAffine2d("Scale",[0.8 1.5],"XReflection",true,'Rotation',[-30 30]);
rout = affineOutputView(size(I),tform);

% Transform image and bounding box labels.
augmentedImage = imwarp(I,tform,"OutputView",rout);
augmentedLabel = imwarp(C,tform,"OutputView",rout);

% Return augmented data.
out = {augmentedImage,augmentedLabel};
end

補助関数 centerCropImageAndLabel は、イメージの中心にトリミング ウィンドウを作成した後、このトリミング ウィンドウを使用してイメージとピクセル ラベル イメージの両方をトリミングします。入力 data と出力 out は 2 要素の cell 配列で、最初の要素がイメージ データ、2 番目の要素がピクセル ラベル イメージ データです。

function out = centerCropImageAndLabel(data,targetSize)
win = centerCropWindow2d(size(data{1}),targetSize);
out{1} = imcrop(data{1},win);
out{2} = imcrop(data{2},win);
end

参考

| | |

関連する例

詳細