В этом примере показано, как создать простой инструмент для редактирования формы произвольной окупаемости инвестиций с помощью другого объекта окупаемости инвестиций. По умолчанию Объекты ROI включают ППМ, которые можно щелкнуть и перетащить для корректировки формы ROI. Можно также добавлять ППМ в интерактивном режиме к любой части границы.Freehand
Еще одним способом редактирования формы свободных ROI, предлагаемым многими популярными программами манипулирования изображениями, является инструмент «ластик» или «кисть». В этом примере реализован один из этих инструментов с использованием другого объекта ROI для редактирования ROI произвольной структуры.
Создайте ROI Freehand, соответствующий форме маски сегментации. Дополнительные сведения об этом процессе см. в разделе Использование ROI Freehand для уточнения масок сегментации.
Считывайте данные МРТ в рабочее пространство.
im = dicomread('knee1.dcm');
Сегментируйте изображение МРТ и выберите две самые большие области маски.
segmentedLabels = imsegkmeans(im,3); boneMask = segmentedLabels==2; boneMask = bwareafilt(boneMask, 1);
Получение координат границ двух сегментированных областей.
blocations = bwboundaries(boneMask,'noholes');
Преобразовать расположения, возвращенные bwboundaries до порядка x, y.
pos = blocations{1};
pos = fliplr(pos);
Отображение изображения.
figure hImage = imshow(im,[]);

Создайте ROI в произвольной форме внутри сегментированной маски.
hf = drawfreehand('Position', pos);

Создайте ROI круга, который будет использоваться в качестве инструмента редактирования ROI ластика или кисти. (Вы можете использовать любой из images.roi.* классы путем внесения небольшого изменения, упомянутого ниже).
he = images.roi.Circle(... 'Center', [50 50],... 'Radius', 10,... 'Parent', gca,... 'Color','r');

Свяжите два прослушивателя событий с ROI круга. Один слушает движение окупаемости инвестиций, а другой - когда движение прекращается. Функция обратного вызова с перемещением ROI, в примере, обеспечивает привязку позиции к местоположениям пикселей, а также изменение цвета (красный/зеленый), чтобы указать, будет ли операция редактирования удалена или добавлена к целевой ROI. Как только ROI редактора прекратит движение, мы создадим соответствующие двоичные маски для ROI редактора и целевого ROI freehand и внесем необходимые правки. Подключение прослушивателя для реагирования при каждом перемещении ROI этого редактора
addlistener(he,'MovingROI', @(varargin)editorROIMoving(he, hf)); addlistener(he,'ROIMoved', @(varargin)editFreehand(hf, he));
Эта анимация показывает операцию добавления и удаления редактирования.

Это функция обратного вызова с перемещением ROI. Эта функция обеспечивает привязку ROI редактора к сетке пикселей и изменяет цвет ROI редактора, чтобы указать, будет ли он добавлен к ROI freehand или удалит область из ROI freehand. Если центр ROI редактора находится за пределами целевого ROI freehand, удаляет операцию, в противном случае она будет «добавлена».
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
Это обратный вызов для редактирования и окупаемости инвестиций, который добавляет или удаляет область окупаемости инвестиций редактора, пересекающую целевую окупаемость инвестиций.
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
addlistener | bwareafilt | bwboundaries | Circle | createMask | dicomread | drawfreehand | Freehand | imsegkmeans | inROI