フリーハンド ROI のサブサンプリングまたは簡略化
この例では、Freehand
ROI オブジェクト内の点をサブサンプリングする、つまり点の数を削減する方法を説明します。
はじめに
関数 drawfreehand
は、滑らかな外観を持つフリーハンドの関心領域 (ROI) を作成します。しかし実際には、ROI のエッジは境界全体に分布する離散点で構成されています。フリーハンド ROI の外観の滑らかさに影響する要因は、次の 2 つです。1) 点の密度、および 2) フリーハンド ROI オブジェクトの Smoothing
プロパティ。
対話形式で描画する際には、マウスの動きによって点の密度が決まります。大きくて複雑な ROI の場合、使用される点の数がかなり多くなることがあります。
Smoothing
プロパティは、境界の外観を制御します。既定では、Freehand
オブジェクトにはシグマ値が 1 でフィルター サイズが 5 のガウス平滑化カーネルが使用されます。この値を変更すると境界の外観のみが変更され、オブジェクトの基となる Position
プロパティは変更されません。
点の既定の密度
点の密度を低下させると、ROI データの格納に必要な領域を減らすのに役立ちます。また、これらの点の数に依存する計算を高速化できます。点の密度を低下させる方法の 1 つは、点をサブサンプリングすることです。たとえば、点を 1 つおきに選択します。
マスクを ROI に変換して、フリーハンド ROI のサンプルを作成します。それぞれの境界ピクセルが ROI の 1 つの点に対応するため、ROI は高密度になります。
im = imread('football.jpg'); bw = im(:,:,1)>200; bw = bwareafilt(bw, 1); bloc = bwboundaries(bw,'noholes'); roipos = fliplr(bloc{1}); imshow(im); hfh = drawfreehand('Position', roipos);
点の密度を可視化するには、ROI 内のそれぞれの点をウェイポイントに変換します。
hfh.Waypoints(:) = true; title('Original density'); snapnow % Zoom in. xlim([80 200]); ylim([70 160]); snapnow
位置の点のサブサンプリング
フリーハンド ROI の Position
プロパティを構成する点をサブサンプリングします。フリーハンド ROI は高密度であるため、サブサンプリングによって、忠実度を損なうことなくサイズを大幅に小さくできます。初期の完全な (細かな) 位置をクエリします。
fpos = hfh.Position;
点を 1 つおきに選択して、サブサンプリングします。
cpos = fpos(1:2:end,:);
ROI の Position プロパティを更新します。
hfh.Position = cpos;
密度を確認するために、すべての点をウェイポイントに変換します。
hfh.Waypoints(:) = true;
title('Simple Subsample');
snapnow
サブサンプリング - 変化率の使用
点のサブサンプリングには、"曲率" が低い点から選択的に点の削除を開始する方法がより適しています。ROI の曲線に近い部分ではなく、ややまっすぐ部分にある点を削除する方が理にかなっています。曲率値を定義する簡単な方法の 1 つは、位置の変化率を測定することです。
変化率を測定します。最初の点の近傍点は最後の点です。
dfpos = diff([fpos(end,:); fpos]);
シンプルなローパス フィルターに基づいて曲率の一時的な測定値を定義します。
cm = sum(abs(conv2(dfpos, ones(3,2),'same')),2);
曲率で並べ替えます。
[~, cmInds] = sort(cm);
曲率値が低い 3/4 の点を選択し、ROI から削除します。
numPointsToCull = round(0.25*size(fpos,1));
これらの位置を削除します。
cpos = fpos; cpos(cmInds(1:numPointsToCull),:) = [];
ROI を更新し、すべてのウェイポイントを有効にして影響を確認します。
hfh.Position = cpos;
hfh.Waypoints(:) = true;
title('Curvature Based Subsample (factor of 4)');
snapnow
サブサンプリング - フリーハンド ROI オブジェクトでの reduce
メソッドの使用
点をサブサンプリングするのにより適した手法は、ROI オブジェクトに対して reduce
メソッドを使用することです。reduce
メソッドは、ROI オブジェクトの Position
プロパティに直接作用します。オプションの入力引数に範囲 [0 1.0] の許容誤差の値を指定して、削除する点の数に影響を与えることができます。許容誤差の既定値は 0.01 です。
Position
プロパティをリセットし、ROI オブジェクトに対して reduce
を呼び出します。
hfh.Position = fpos; reduce(hfh); % View the updated ROI, turning all the points into waypoints to see the % impact. hfh.Waypoints(:) = true; title('Subsampling using reduce method'); snapnow
対話型のサブサンプリング
サブサンプリングを行うもう 1 つの方法は、イベントを使用してこのプロセスを容易にすることです。まず、フリーハンド ROI で使用する点の数を対話形式で変更するリスナーを作成します。フリーハンド オブジェクトの UserData
プロパティを使用して、完全な解像度の Position
データと許容誤差の現在の値をキャッシュします。次に、新しい
を作成し、それをフリーハンド オブジェクトの uimenu
UIContextMenu
の親にすることによって、カスタム コンテキスト メニューを ROI オブジェクトに追加します。このメニュー オプションを使用して、ROI を "ファイナライズ" することで、一時的なキャッシュが削除されます。
元の ROI を復元し、元の位置を UserData の曲率測定値と共にキャッシュします。
hfh.Waypoints(:) = true; hfh.UserData.fpos = fpos; hfh.UserData.tol = 0;
マウスのスクロールに応答します。
h = gcf; h.WindowScrollWheelFcn = @(h, evt) changeSampleDensity(hfh, evt);
コンテキスト メニューを追加して ROI をファイナライズし、必要なクリーンアップを実行します。
uimenu(hfh.UIContextMenu, 'Text','Finalize',... 'MenuSelectedFcn', @(varargin)finalize(hfh)); title('Scroll to change density interactively');
対話型のサブサンプリングのアニメーション
コールバック関数 - マウスのスクロールに基づくサンプルの密度の変更
この関数はスクロール操作に対して呼び出されます。上にスクロールすると密度が上昇し、下にスクロールすると密度が低下します。これにより、保持する点の数を対話形式で選択できます。
function changeSampleDensity(hfh, evt) % Restore Position property of ROI. hfh.Position = hfh.UserData.fpos; % Change tolerance by a fixed amount based on the direction of the scroll. % This code changes the tolerance by 0.01 for every scroll increment. tol = hfh.UserData.tol + 0.01 * (evt.VerticalScrollCount); % Restrict the range of tolerance values to be from 0 to 0.15, which is the % useful range. tol = max(min(tol, 0.15), 0); % Call |reduce| with the specified tolerance. reduce(hfh,tol); hfh.UserData.tol = tol; % Update the ROI and turn all the points into waypoints to show the % density. hfh.Waypoints(:) = true; end
コールバック関数 - フリーハンド ROI のファイナライズ
フリーハンド ROI を削除して、サブサンプリングされた点を使用して新しいフリーハンド ROI を作成し、領域に保存します。
function finalize(hfh) h = ancestor(hfh, 'figure'); % Reset the mouse scroll wheel callback. h.WindowScrollWheelFcn = []; % Save finalized set of points. pos = hfh.Position; % Delete and create a new Freehand ROI with the new |Position| value. delete(hfh); drawfreehand(gca, 'Position', pos); end
参考
bwareafilt
| bwboundaries
| drawfreehand
| Freehand