フリーハンド ROI 編集ツールの作成
この例では、別の ROI オブジェクトを使用してフリーハンド ROI の形状を編集するシンプルなツールの作成方法を説明します。既定では、
ROI オブジェクトには、クリック アンド ドラッグして ROI の形状を調整できるウェイポイントが含まれています。また、境界の任意の部分にウェイポイントを対話形式で追加することもできます。フリーハンド
フリーハンド ROI の形状を編集する別の方法として、多くの一般的なイメージ操作プログラムは '消しゴム' または 'ブラシ' ツールを提供しています。この例では、これらのツールのいずれかを実装し、別の ROI オブジェクトを使用してフリーハンド ROI を編集します。
フリーハンド ROI の作成
セグメンテーション マスクの形状に従うフリーハンド ROI を作成します。このプロセスの詳細については、フリーハンド ROI を使用したセグメンテーション マスクの調整を参照してください。
MRI データをワークスペースに読み取ります。
im = dicomread('knee1.dcm');
MRI イメージをセグメント化し、マスクから最も大きい 2 つの領域を選択します。
segmentedLabels = imsegkmeans(im,3); boneMask = segmentedLabels==2; boneMask = bwareafilt(boneMask, 1);
セグメント化された 2 つの領域の境界の座標を取得します。
blocations = bwboundaries(boneMask,'noholes');
bwboundaries
によって返される位置を x、y の順に変換します。
pos = blocations{1}; pos = fliplr(pos);
イメージを表示します。
figure hImage = imshow(im,[]);
セグメント化されたマスク内にフリーハンド ROI を作成します。
hf = drawfreehand('Position', pos);
フリーハンド ROI 編集ツールの作成
円 ROI を作成し、消しゴムまたはブラシの機能を持つ ROI 編集ツールとして使用します (以下のように、いずれかの images.roi.*
クラスに少し変更を加えて使用できます)。
he = images.roi.Circle(... 'Center', [50 50],... 'Radius', 10,... 'Parent', gca,... 'Color','r');
2 つのイベント リスナーを円 ROI に関連付けます。1 つは ROI の移動をリッスンし、もう 1 つは移動の停止をリッスンします。この ROI 移動コールバック関数の例は、その位置をピクセル位置にスナップし、さらに色の変化 (赤/緑) によって、編集操作でターゲット フリーハンド ROI に対する削除または追加が行われるかどうかを示します。エディター ROI が移動を停止したら、エディター ROI に対応するバイナリ マスクとターゲット フリーハンド ROI を作成し、必要な編集を行います。最後に、更新されたマスクを変換してフリーハンド ROI オブジェクトに戻します。リスナーを有効にして、このエディター ROI が移動するたびに応答するようにします。
addlistener(he,'MovingROI', @(varargin)editorROIMoving(he, hf)); addlistener(he,'ROIMoved', @(varargin)editFreehand(hf, he));
フリーハンド ROI の対話形式での編集
次のアニメーションは、追加および削除を行う編集操作を示します。
これは ROI 移動コールバック関数です。この関数は、エディター ROI をピクセル グリッドにスナップし、エディター ROI の色の変化によってフリーハンド ROI への領域の追加やフリーハンド ROI からの領域の削除が行われるかどうかを示します。エディター ROI の中心がターゲット フリーハンド ROI の外側にある場合、操作が削除されます。そうでない場合は、'追加' が行われます。
function editorROIMoving(he, hf) % Snap editor ROI to grid he.Position = round(he.Position); % Check if the circle ROI's center is inside or outside the freehand ROI. center = he.Center; isAdd = hf.inROI(center(1), center(2)); if isAdd % Green if inside (since we will add to the freehand). he.Color = 'g'; else % Red otherwise. he.Color = 'r'; end end
これは、ターゲット フリーハンド ROI と交差するエディター ROI の領域を追加または削除する、フリーハンド ROI 編集コールバックです。
function editFreehand(hf, he) % Create a mask for the target freehand. tmask = hf.createMask(); [m, n,~] = size(tmask); % Include the boundary pixel locations boundaryInd = sub2ind([m,n], hf.Position(:,2), hf.Position(:,1)); tmask(boundaryInd) = true; % Create a mask from the editor ROI emask = he.createMask(); boundaryInd = sub2ind([m,n], he.Position(:,2), he.Position(:,1)); emask(boundaryInd) = true; % Check if center of the editor ROI is inside the target freehand. If you % use a different editor ROI, ensure to update center computation. center = he.Center; % isAdd = hf.inROI(center(1), center(2)); if isAdd % Add the editor mask to the freehand mask newMask = tmask|emask; else % Delete out the part of the freehand which intersects the editor newMask = tmask&~emask; end % Update the freehand ROI perimPos = bwboundaries(newMask, 'noholes'); hf.Position = [perimPos{1}(:,2), perimPos{1}(:,1)]; end
参考
dicomread
| imsegkmeans
| bwareafilt
| bwboundaries
| drawfreehand
| Freehand
| Circle
| addlistener
| inROI
| createMask