Editing impoly polygons in a GUIDE app

In a GUIDE app, I want to draw polygons on an image (say 4 polygons), then copy the polygons and display on a different image, then edit those polygons and save the changes with the new image. AFAIK, I need to use impoly because I have R2017b. I click a button on the GUI, which runs a function where I use h = impoly. I am experimenting with addNewPositionCallback inside this function, but after this function has executed, I don't see any way to get to that polygon again to detect changes. When I display a particular image, I want to draw the polygons associated with that image (not a problem), but the problem comes when I want to detect edits that the user can then make to the polygons associated with that image. Any examples of doing this would be appreciated. Again, I don't have a problem storing polygons and drawing them later, the problem is editing them and saving the changes.
Thanks
Ron

1 Comment

RonE
RonE on 23 Aug 2019
Edited: RonE on 23 Aug 2019
I have a function that is called when a user clicks a button on the GUI:
function handles = draw_polygon(handles)
h = impoly; %allow user to draw polygon
fcn = @posChanged;
addNewPositionCallback(h, fcn);
points = h.getPosition;
...
end
function posChanged(pos)
pos %write out for testing
end
posChanged gets called when I move vertices of the polygon, but I cannot save the changes because I do not have access to handles in posChanged. Is there a way to pass handles into posChanged? handles is essentially a place where I store "global" variables in the GUI app.
Ron

Sign in to comment.

 Accepted Answer

"after this function has executed, I don't see any way to get to that polygon again to detect changes"
Once the callback function is finished, all variable values within the function are lost forever unless you save them (exceptions are global and persistant variables which are not recommended).
You can use guidata() to save variables to your GUI so when you enter a callback function, those values can be retreived. Here's a demo that stores/retreives data in/from the GUI figure itself but you could chose any GUI object.
function myCallbackFunction(hObject, event, handles)
h = impoly(. . .);
dat = guidata(handles.figure); %assuming the handle to your figure is named 'figure'
if ~isfield(dat,'PolyHandles')
% add the field if it doesn't exist already
dat.PolyHandles = [];
end
dat.PolyHandles(end+1) = h; %add new handle to end
guidata(handles.figure,dat); %store the updated data
end
To clear the handles,
dat = guidata(handles.figure);
dat.PolyHandles = [];
guidata(handles.figure,dat);
Once you have the handles, you can do everything in your question: edit them, copy them to another image, etc.

14 Comments

Thanks Adam, but I think this can be done more simply. Here is what I have for lots of functions. I guess it's one line simpler. handles is already passed into the function so no need to retrieve anything.
function myCallbackFunction(hObject, event, handles)
h = impoly(. . .);
%dat = guidata(handles.figure); %assuming the handle to your figure is named 'figure'
if ~isfield(handles, 'PolyHandles')
% add the field if it doesn't exist already
handles.PolyHandles = [];
end
handles.PolyHandles(end+1) = h; %add new handle to end
guidata(hObject, handles); %store the updated data
end
I tried storing the handle to an impoly in handles, but when I tried to use it later, Matlab said the handle to my impoly has been deleted. It was still there but apparently empty. I assume because it was no longer displayed on the figure. It seems I will have to store the polygon shape, then redraw it and get a new handle. But my big problem is still capturing user edits to the polygon.
Adam Danz
Adam Danz on 24 Aug 2019
Edited: Adam Danz on 26 Aug 2019
It looks like you applied my answer to the handles structure which is a fine choice.
"Matlab said the handle to my impoly has been deleted. "
The handle and the object are two different things. You can have an object and delete the handle. And you can have a handle and delete the object but the handles becomes virtually useless.
"It seems I will have to store the polygon shape, then redraw it and get a new handle. "
Maybe that could be a solution but there might be a better one depending on your goals. Why are the polygons being deleted? How are they being deleted? Why do they need to come back into existance? If I get a better idea of what you're doing I might be able to make some suggestions. For example, you can turn off/on the visibility of an object without deleting/recreating it.
Adam, Thank you for the response. I will try to explain. I have several images (frames) that can be displayed, each with its own set of polygons. I want the user to be able to draw and edit the polygons associated with each image. I have it working where I can draw polygons, save them, and draw them later on the correct image. (When I say the polygons are 'deleted', they must no longer be drawn when I move to a different image.) My problem is that I would like to be able to move vertices, add vertices, drag, etc the polygons on each image and save the changes. Don't know how to do this. I have managed to get a function to be called using addNewPositionCallback as I described above, but the only parameters my function posChanged takes is the updated points of the polygon, so I don't have enough info to save the updated polygon. I don't know which image frame it is associated with. Ideally I would like to have my posChanged function receive the polygon points (pos) and 'handles' from the GUI. Or just pass it any parameter other than the points.
Ron
" Ideally I would like to have my posChanged function receive the polygon points (pos) and 'handles' from the GUI. Or just pass it any parameter other than the points."
Isn't the first input to the addnewpositioncallback() function the polygon handle? You could pass the handle into the addNewPositionCallback function and then pass it again into your response function.
addNewPositionCallback(h,@(p) newPosFcn(p,h));
function newPosFcn(p,h)
% h is the handle to your object.
% p is its position
end
"Isn't the first input to the addnewpositioncallback() function the polygon handle? If you pass the handle into that function (which, I believe is input #1) then you can get the point positions."
Yes:
h = impoly; %allow user to draw polygon
fcn = @posChanged;
addNewPositionCallback(h, fcn);
But posChanged receives one paramter. I don't know what goes on behind the scenes to specify this. I can pass something different than the updated polygon points into posChanged, by changing the middle line to fcn = @posChanged(handles) for example, but that is still only one paramter. I need two. Maybe the updated polygon points are inside handles somewhere, but I don't see them.
Ron
Pass the object handle into the addNewPositionCallback function. Then you can use object functions to pull info out of the object handle.
Here's a list of object function that may be helpful.
also see
methods impoly %Run this line to produce the results below
Methods for class impoly:
addNewPositionCallback getPosition resume setPosition
createMask getPositionConstraintFcn setClosed setPositionConstraintFcn
delete impoly setColor setVerticesDraggable
getColor removeNewPositionCallback setConstrainedPosition wait
Here's a demo that pulls out the (x,y) coordinates of the vertices.
addNewPositionCallback(h,@(p) newPosFcn(p,h));
function newPosFcn(p,h)
verts = getPosition(h)
end
Think I may have found the missing link:
h = impoly;
fcn = @(a, b) posChanged(handles, h);
addNewPositionCallback(h, fcn);
...
posChanged(handles, h)
h.getPosition %Get updated polygon vertices
%Assign to structure in handles, etc.
end
This should work for me. New discoveries are often made the first few minutes after starting to work in the morning.
Ha! See my comment above. :)
Yes it's the same thing, huh? Why does it not seem to matter what is in the "arglist", the p in fcn = @(p) newPosFcn(p,h) ? I can use p or p,q for example and the program functions the same. Why does there not need to be 2 arguments there?
Ron
Adam Danz
Adam Danz on 26 Aug 2019
Edited: Adam Danz on 26 Aug 2019
First, congrats on solving this prior to seeing my comment. People always learn more when they solve it on their own and those 'ah-ha' moments make lasting changes in the brain.
To address your question, anonymous functions define an expression and its inputs but they also can store additional pre-existing variables that the expression requires for evaluation.
Check out Matlab's explanation for more detail.
When we create a callback function associated with an impoly handle like this, how long does the connection to the function exist? As long as the handle exists or what? Even if the handle were saved in a mat file? Or can the function connect to only one polygon at a time?
Ron
Adam Danz
Adam Danz on 26 Aug 2019
Edited: Adam Danz on 26 Aug 2019
Yes, as long as the handle exists. Think of it this way. When you assign the addNewpositionCallback function to a handle, that function and all of its inputs are stored as a property of that handle. When the function is called, it invokes the function using the inputs stored within the handle's addNewPositionCallback function.
If you save the handle to a mat file, clear your workspace, and then load the handle back in, it should behave in the same way even if other imploy objects have similar callback functions.
You could test that, of course.
It looks like I have it working pretty well, although I need to redraw the frame when the user stops editing (dragging a vertex, etc). Thanks for your help. I don't know how to detect when the user stops editing. Maybe I would have to use a timer. You have a any idea?
Maybe you could add a button to your figure. After the fig is created, this line below will add a button to the bottom, left corner.
uicontrol('style','pushbutton','Units','normalize','position',[.05,.05,.08,.05],'String','Done','Callback',@yourfunc)
You'll need to write a sensible callback function that sets some kind of flag to signal the editing is done to execute the next steps.

Sign in to comment.

More Answers (0)

Categories

Find more on Interactive Control and Callbacks in Help Center and File Exchange

Products

Release

R2017b

Asked:

on 23 Aug 2019

Commented:

on 26 Aug 2019

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!