Main Content

マスクを使用したブロック化されたイメージの効率的な処理

この例では、マスクを使用して関心領域 (ROI) を分離することによって、ブロック化されたイメージを効率的に処理する方法を説明します。

大きなイメージのソースのなかには、イメージのごく一部にのみ意味のあるデータが含まれているものがあります。意味のあるデータが含まれる ROI に処理を制限することにより、合計処理時間を改善できます。マスクを使用して ROI を定義します。マスクは、true ピクセルが ROI を表す論理イメージです。

ブロック化されたイメージのワークフローでは、マスクはイメージ データと同じ空間領域を表しますが、イメージと同じサイズである必要はありません。ワークフローの効率をさらに向上させるには、粗いイメージからマスクを、特にメモリに収まるものを作成します。その後、粗いマスクを使用して、より細かいイメージを処理します。

CAMELYON16 データ セットのイメージ tumor_091.tif の変更したバージョンを使用して、ブロック化されたイメージを作成します。元のイメージは、腫瘍組織が含まれるリンパ節の学習イメージです。元のイメージには 8 つの解像度レベルがあり、最も細かいレベルの解像度は 53760 x 61440 です。変更したイメージには、3 つの粗い解像度レベルのみが含まれています。変更したイメージの空間参照は、縦横比が一定に維持され、各レベルで特徴がレジストレーションされるように調整されています。

bim = blockedImage("tumor_091R.tif");

関数 bigimageshow を使用してブロック化されたイメージを表示します。

bigimageshow(bim);

マスクの作成

最も粗いレベルのイメージ サイズを決定します。

coarseLevel = bim.NumLevels; % The highest numbered level is the coarsest level
coarseLevelSize = bim.Size(coarseLevel,:)
coarseLevelSize = 1×3

   625   670     3

最も粗い解像度レベルのイメージを取得します。

imLowRes = gather(bim);

イメージの領域分割アプリを使用して、粗いイメージからマスクを生成できます。アプリはグレースケール入力イメージを想定しているため、粗いイメージから輝度チャネルを抽出しなければなりません。

imLowResL = rgb2lightness(imLowRes);

"イメージの領域分割" アプリを実行するには、コマンド ウィンドウで次のコマンドを入力します。

imageSegmenter(imLowResL)

マスクを定義したら、BW としてマスクをエクスポートするか、アプリがマスクを作成するのに使用したコードをエクスポートします。例のこの節では、アプリからエクスポートしたコードを使用します。次のコードを実行して、粗い入力イメージからマスクを作成して表示します。

%----------------------------------------------------
% Normalize input data to range in [0,1].
Xmin = min(imLowResL(:));
Xmax = max(imLowResL(:));
if isequal(Xmax,Xmin)
    imLowResL = 0*imLowResL;
else
    imLowResL = (imLowResL - Xmin) ./ (Xmax - Xmin);
end

% Threshold image - global threshold
BW = imbinarize(imLowResL);

% Invert mask
BW = imcomplement(BW);

% Open mask with square
width = 3;
se = strel("square", width);
BW = imopen(BW, se);
%----------------------------------------------------

imshow(BW)

入力マスクと同じ空間参照を使用して、このマスクからブロック化されたイメージを作成します。

bmask = blockedImage(BW,WorldEnd=bim.WorldEnd(3,1:2));

半透明の緑のオーバーレイとして、元のブロック化されたイメージの上にマスクを表示します。

h = bigimageshow(bim);
showlabels(h,bmask,AlphaDat=bmask,Alphamap=[0 0.5],Colormap=[0 0 0; 0 1 0])

包含しきい値の調整による関心領域のカバー

関数 apply は、ブロック化されたイメージを一度に 1 ブロックずつ処理します。名前と値の引数 InclusionThreshold をマスクと共に使用して、関数 apply が使用するブロックを指定できます。包含しきい値は、apply がブロックを処理するために true でなければならないマスク ピクセルの割合を指定します。

apply が既定の包含しきい値 0.5 を使用して処理するブロックを強調表示します。この関数は、緑色で強調表示された中央のブロックのみを処理します。

h = bigimageshow(bim);
showmask(h,bmask,1)
title("Mask with Default Inclusion Threshold")

イメージ内のより多くのブロックを処理するには、包含しきい値を減らします。

showmask(h,bmask,1,InclusionThreshold=0.4)
title("InclusionThreshold = 0.4")

マスク内に true ピクセルが少なくとも 1 つ含まれるすべてのブロックを処理することもできます。このオプションを使用するには、名前と値の引数 InclusionThreshold0 として指定します。必ずしもイメージ内のすべてのブロックが含まれるわけではないことに注意してください。

showmask(h,bmask,1,InclusionThreshold=0)
title("InclusionThreshold = 0")

任意の値の InclusionThreshold を指定してマスクを使用すると、apply がフル イメージに含まれる一部のブロックのみを処理するため、合計実行時間が減少します。解像度が大きいほど、また処理パイプラインが複雑であるほど、マスクを使用するメリットが著しくなります。

フル イメージに対するフィルター処理の実行時間を測定します。

tic
bout = apply(bim, ...
    @(bs)imnlmfilt(bs.Data,DegreeOfSmoothing=15));
tFullProcessing = toc;

ROI に含まれるブロックのみに対するフィルター処理の実行時間を測定します。

bls = selectBlockLocations(bim,Mask=bmask,InclusionThreshold=0);
tic
boutMasked = apply(bim, ...
    @(bs)imnlmfilt(bs.Data,DegreeOfSmoothing=15), ...
    BlockLocationSet=bls);
tMaskedProcessing = toc;

bigimageshow(boutMasked)
defaultBlockSize = bim.BlockSize(1,:);
title("Processed Image Using Mask with Default BlockSize = [" + ...
    num2str(defaultBlockSize)+"]");

フル イメージを処理する場合の実行時間を、ROI に含まれるブロックのみを処理する場合の実行時間と比較します。

disp("Speedup using mask: " + ...
    num2str(tFullProcessing/tMaskedProcessing) + "x");
Speedup using mask: 1.6918x

ブロック サイズの調整による関心領域の輪郭の追従

ブロック サイズを減らすと、ROI をより厳密に囲むことができます。ブロック サイズによっては、apply が処理する ROI 外のピクセル数が少なくなるため、これにより実行時間が減少します。ただし、ブロック サイズが小さすぎると、大量のブロックを処理するためのオーバーヘッドが処理ピクセル数の減少を相殺するため、パフォーマンスが低下します。

apply が小さいブロック サイズを使用して処理するブロックを強調表示します。ブロック サイズを指定するには、名前と値の引数 BlockSize を使用します。

blockSize = [512 512];
h = bigimageshow(bim);
showmask(h,bmask,1,BlockSize=blockSize,InclusionThreshold=0)
title("BlockSize = [" + num2str(blockSize) + "] | InclusionThreshold = 0")

ブロック サイズを減らした場合の ROI 内の全ブロックに対するフィルター処理の実行時間を測定します。

bls = selectBlockLocations(bim,Mask=bmask,InclusionThreshold=0);
tic
boutMasked = apply(bim, ...
    @(bs)imnlmfilt(bs.Data,DegreeOfSmoothing=15), ...
    BlockLocationSet=bls);
tSmallerBlockProcessing = toc;

bigimageshow(boutMasked);
title("Processed Image Using Mask with BlockSize = [" + ...
    num2str(blockSize) + "]");

小さいブロックで ROI 全体を処理する場合の実行時間を、元のブロックで ROI 全体を処理する場合の実行時間と比較します。

disp("Additional speedup using mask with decreased block size: " + ...
    num2str(tMaskedProcessing/tSmallerBlockProcessing) + "x");
Additional speedup using mask with decreased block size: 0.9917x

参考

| |