gusucode.com > vision工具箱matlab源码程序 > vision/+vision/+internal/+cascadeTrainer/+tool/EnhancedROI.m
% EnhancedROI is a rectangle with a close button and a text label % Copyright 2016 The MathWorks, Inc. classdef EnhancedROI < handle properties(Access=private) Roi; ImageHandle; AxesHandle; end properties(Dependent) IsValid; IsSelected; BBox; CategoryID; CopiedData; end events Delete Move Copy Cut end methods %------------------------------------------------------------------ function this = EnhancedROI(bbox, hAxes, hImage, catID, color, label, ... showLabel) this.ImageHandle = hImage; this.AxesHandle = hAxes; if isa(bbox, 'imrect') this.Roi = bbox; else this.Roi = iptui.imcropRect(hAxes, bbox - [0.5 0.5 0 0], this.ImageHandle); end this.Roi.setColor(color); this.IsSelected = false; userData.catID = catID; set(this.Roi, 'UserData', userData); enhanceROIAppearance(this, color, label, showLabel) end function copiedData = get.CopiedData(this) copiedData.bbox = this.BBox + [0.5 0.5 0 0]; copiedData.categoryID = this.CategoryID; userData = get(this.Roi, 'UserData'); copiedData.categoryName = userData.category.String; copiedData.color = this.Roi.getColor(); end %------------------------------------------------------------------ function bbox = get.BBox(this) bbox = this.Roi.getPosition(); end %------------------------------------------------------------------ function catID = get.CategoryID(this) userData = get(this.Roi, 'UserData'); catID = userData.catID; end %------------------------------------------------------------------ function isValid = get.IsValid(this) isValid = this.Roi.isvalid(); end %------------------------------------------------------------------ function tf = get.IsSelected(this) if this.Roi.isvalid() tf = strcmpi(get(this.Roi, 'Selected'), 'on'); else tf = false; end end %------------------------------------------------------------------ function set.IsSelected(this, val) if ~this.Roi.isvalid() return; end roiPatch = findobj(this.Roi, 'type', 'patch'); if val set(this.Roi, 'Selected', 'on'); set(roiPatch, 'FaceColor', 'y'); else set(this.Roi, 'Selected', 'off'); set(roiPatch, 'FaceColor', 'none'); end end %------------------------------------------------------------------ function delete(this) if this.IsValid userData = get(this.Roi, 'userData'); delete(userData.delIcon) delete(userData.category) delete(this.Roi); end end %------------------------------------------------------------------ function setTextLabelVisible(this, showLabel) if this.IsValid userData = get(this.Roi, 'userData'); if showLabel userData.category.Visible = 'on'; else userData.category.Visible = 'off'; end end end end methods(Access=private) %------------------------------------------------------------------ function enhanceROIAppearance(this, catColor, catName, showLabel) if ~this.IsValid return; end roi = this.Roi; % Specify the order in which objects are drawn to avoid Z % buffer fighting (which messes up the patch color when we % select an ROI and zoom into the image) set(this.AxesHandle, 'SortMethod', 'childorder'); userData = get(roi,'UserData'); userData.delIcon = this.createDeleteIcon(); userData.category = this.createCategoryLabel(catColor, catName,... showLabel); set(roi,'UserData',userData); % Set SelectionHighlight property to OFF % This is required to ensure that the IMRECT corner marker does % not block the delete text box set(roi, 'SelectionHighlight','off'); roiChildren = get(roi, 'Children'); set(roiChildren, 'SelectionHighlight','off'); % Set patch properties roiPatch = findall(roi, 'Type', 'Patch'); set(roiPatch, 'FaceAlpha', 0.5); % Set patch callback to select/ unselect ROIs iptaddcallback(roiPatch, 'ButtonDownFcn', @clickOnROI); this.setupContextMenu(roiPatch); % Constrain drawing of ROIs this.constrainROI(); % Add callback to reposition delete button if moved roi.addNewPositionCallback(@this.doReposition); % Nested Subfunctions of enhanceROIAppearence %---------------------------------------------------------- function clickOnROI(~,~) fig = this.ImageHandle.Parent.Parent; clickType = get(fig, 'SelectionType'); leftClick = strcmp(clickType, 'normal'); ctrlPressed = strcmp(get(fig, 'CurrentModifier'), 'control'); rightClick = strcmp(clickType,'alt')& isempty(ctrlPressed); ctrlClick = strcmp(clickType,'alt')& ~isempty(ctrlPressed); if leftClick || rightClick if ~this.IsSelected roiHandles = findall(this.AxesHandle, 'tag',... 'imrect','Selected','on'); if ~isempty(roiHandles) roiPatches = findall(roiHandles,'Type',... 'Patch'); unSelectROI(roiHandles, roiPatches); end selectROI(roi, roiPatch); end elseif ctrlClick if this.IsSelected unSelectROI(roi, roiPatch); else selectROI(roi, roiPatch); end end drawnow; end end %---------------------------------------------------------- function constrainROI(this) roiPosition = this.BBox; [y_extent, x_extent, ~] = size(get(this.ImageHandle,'CData')); % Get image boundaries xLimit = [0.5 x_extent+0.5]; yLimit = [0.5 y_extent+0.5]; if roiPosition(1) < xLimit(1) % Drawn beyond left axis this.Roi.setPosition([xLimit(1) roiPosition(2) ... roiPosition(3)-(xLimit(1)-roiPosition(1)) roiPosition(4)]); elseif roiPosition(1)+roiPosition(3) > xLimit(2) % Drawn beyond right axis this.Roi.setPosition([roiPosition(1) roiPosition(2) ... xLimit(2)-roiPosition(1) roiPosition(4)]); elseif roiPosition(2) < yLimit(1) % Drawn above top axis this.Roi.setPosition([roiPosition(1) yLimit(1) ... roiPosition(3) roiPosition(4)-(yLimit(1)-roiPosition(2))]); elseif roiPosition(2)+roiPosition(4) > yLimit(2) % Drawn above bottom axis this.Roi.setPosition([roiPosition(1) roiPosition(2) ... roiPosition(3) yLimit(2)-roiPosition(2)]); end end %---------------------------------------------------------- function doReposition(this, newPosition) userData = get(this.Roi,'UserData'); delIcon = userData.delIcon; category = userData.category; set(delIcon,'pos',... [newPosition(1)+newPosition(3) newPosition(2)]); [y_extent, x_extent, ~] = size(get(this.ImageHandle,'CData')); % Get image boundaries xLimit = [0.5 x_extent+0.5]; yLimit = [0.5 y_extent+0.5]; % check if upper left border is outside axes if newPosition(1) < min(xLimit) || ... newPosition(1) > max(xLimit)|| ... newPosition(2) < min(yLimit)|| ... newPosition(2) > max(yLimit) set(delIcon,'Visible','off'); else set(delIcon,'Visible','on'); end labelPos = [newPosition(1), ... newPosition(2)+newPosition(4)+category.Extent(4)*0]; set(category, 'pos', labelPos); notify(this, 'Move'); end %---------------------------------------------------------- function delIcon = createDeleteIcon(this) roiPosition = this.BBox; delIcon = text('parent',this.AxesHandle,... 'pos',[roiPosition(1)+roiPosition(3) roiPosition(2)],... 'string','\fontsize{4} \bf\fontsize{6}X\rm\fontsize{4} ',... 'tag','delIcon',... 'edgecolor','w',... 'color','w',... 'backgroundcolor',[0.7 0 0],... 'horizontalalignment','center',... 'buttondownfcn',@this.doDeleteROI,... 'Clipping','on'); % Anonymous function for setting mouse pointer to arrow while % hovering over delete button. enterFcn = @(figHandle, currentPoint)... set(figHandle, 'Pointer', 'arrow'); iptSetPointerBehavior(delIcon, enterFcn); iptPointerManager(this.AxesHandle.Parent); end %---------------------------------------------------------- function category = createCategoryLabel(this, catColor, catName, ... showLabel) roiPosition = this.BBox; category = text('parent', this.AxesHandle, ... 'backgroundcolor', catColor, 'string', catName, ... 'tag', 'category', 'Interpreter', 'none',... 'Clipping','on'); labelPos = [roiPosition(1), ... roiPosition(2)+roiPosition(4)]; category.Position = labelPos; if showLabel category.Visible = 'on'; else category.Visible = 'off'; end end %---------------------------------------------------------- function doDeleteROI(this, ~, ~) userData = get(this.Roi, 'UserData'); delete(userData.delIcon) delete(userData.category) delete(this.Roi); notify(this, 'Delete'); end %---------------------------------------------------------- function setupContextMenu(this, roiPatch) % Set patch context menu patchRightClick = uicontextmenu('Parent', this.AxesHandle.Parent); set(roiPatch, 'UIContextMenu', patchRightClick); uimenu(patchRightClick,'Label','Copy', ... 'Callback', @(~,~)notify(this, 'Copy'), ... 'Accelerator', 'C'); uimenu(patchRightClick,'Label','Cut', ... 'Callback', @(~,~)notify(this, 'Cut'), ... 'Accelerator', 'X'); l = findobj(this.Roi, 'type', 'line'); contextMenuHandle = get(l(1), 'UIContextMenu'); delete(contextMenuHandle); end end end %------------------------------------------------------------------ % Change patch and bounding box colors to indicate selection function selectROI(roi, roiPatch) % Change patch color to yellow set(roiPatch, 'FaceColor', 'y'); set(roi, 'Selected','on'); end %------------------------------------------------------------------ % Change patch and bounding box colors to indicate de-selection function unSelectROI(roi, roiPatch) % Change patch color to none set(roiPatch, 'FaceColor', 'none'); set(roi, 'Selected','off'); end