В этом примере показов, как создать простой инструмент для редактирования формы информации только для чтения freehand с помощью другого объекта информации только для чтения. По умолчанию
Объекты информация только для чтения включают путевые точки, которые можно кликнуть и перетащить, чтобы настроить форму ROI. Можно также добавить путевые точки в интерактивном режиме к любой части контура.Freehand
Другой способ редактирования формы ROI freehand, предлагаемый многими популярными программами преобразования изображения, - это инструмент 'eraser' или 'brush'. Этот пример реализует один из этих инструментов, используя другую информацию только для чтения объект для редактирования информации только для чтения freehand.
Создайте информацию только для чтения 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,[]);
Создайте информацию только для чтения freehand внутри сегментированной маски.
hf = drawfreehand('Position', pos);
Создайте информация только для чтения круга, который будет использоваться как инструмент редактирования ROI ластика или кисти. (Можно использовать любой из images.roi.*
классы путем внесения небольших изменений, упомянутых ниже).
he = images.roi.Circle(... 'Center', [50 50],... 'Radius', 10,... 'Parent', gca,... 'Color','r');
Связать два прослушивателей событий с информацией только для чтения Circle. Один слушает движение ROI, а другой слушает, когда движение останавливается. Функция ROI-обратного вызова, пример, гарантирует, что его положение привязывается к пиксельным местоположениям, а также чтобы изменить цвет (красный/зеленый), чтобы указать, будет ли операция редактирования удалена или добавлена к целевому ROI freehand. Как только информация только для чтения редактора перестанет двигаться, мы создадим соответствующие бинарные маски для информации только для чтения редактора и целевого freehand информации только для чтения и сделаем необходимую редакцию. Наконец, мы преобразуем обновленную маску обратно в информацию только для чтения freehand объекта. Подключите прослушиватель, чтобы реагировать каждый раз, когда этот редактор информация только для чтения перемещается
addlistener(he,'MovingROI', @(varargin)editorROIMoving(he, hf)); addlistener(he,'ROIMoved', @(varargin)editFreehand(hf, he));
Эта анимация показывает операцию добавления и удаления редактирования.
Это - информация только для чтения движущаяся функция обратного вызова. Эта функция гарантирует, что редактор информации только для чтения привязок к пиксельной сетке и изменяет цвет информации только для чтения редактора, чтобы указать, будет ли он добавлять к информации только для чтения freehand или удалять область из информации только для чтения freehand. Если центр информации только для чтения редактора находится вне целевой информации только для чтения freehand, удаляет операцию, в противном случае она 'add'.
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
Это - обратный коллбэк edit freehand ROI, который добавляет или удаляет область ROI редактора, которая пересекает целевую ROI freehand.
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