Problem with uiwait; broken by impoly / imroi / roipoly

I need a GUI where the user can draw several polygons in an image, and when he is done, the polygon vertices are saved.
So I created a GUI with guide, with an axes with the image, and two pushbuttons. I used 'uiwait' as proposed in guide at the end of the Opening Function. One button 'New' let's the user draw a polyon using 'impoly'. The other button 'OK' calls 'uiresume', so that the code jumps to the Output Function.
The problem is:
Apparently the 'imroi' functions like 'impoly' break 'uiwait' early, and as soon as the first polygon is closed, the Output Function is called. I found two other posts indicating this. The only answer they found was to use 'roipolyold'. But since it is supposed to be removed in future releases, and I'm otherwise quite happy with 'imploly', I would really like to find another solution. I tried avoiding 'uiwait' und using 'waitfor' instead, but it always closed the figure right after opening and then got stuck on 'waitfor'.
I will be happy about any clues or ideas as to how I could get around this. Thanks!

Réponses (4)

Image Analyst
Image Analyst le 28 Août 2014

0 votes

Store the results of each polygon (the vertex coordinates) in a global variable cell array. Each time you click the button and draw a polygon, by whatever method, add it to the cell array variable as a new cell.

8 commentaires

Aline
Aline le 3 Sep 2014
Thanks, but this didn't help me with the problem with uiwait. As soon as I use impoly for the first time, the GUI closes.
Image Analyst
Image Analyst le 3 Sep 2014
Modifié(e) : Image Analyst le 3 Sep 2014
Huh? Why does your gui shut down? You must be doing something to shut it down. Do you have a script, or a GUIDE-based gui?
I don't even use uiwait or uiresume in code around calls to roipoly. Here is for a pushbutton callback from one of my functions:
%=====================================================================
% --- Executes on button press in btnDrawNewMask.
function btnDrawNewMask_Callback(hObject, eventdata, handles)
% hObject handle to btnDrawNewMask (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
try
% Prompt user to draw a region on the image.
message = sprintf('Draw a polygon (with left clicks) over the image.\nRight click the last vertex point to finish drawing.\n\nIMPORTANT NOTE: you must move inside the polygon and\neither (a) double-click, or (b) right click and select Create Mask from the context menu\nin order to continue towards saving the mask.');
msgboxw(message);
% Get binary image that is a mask representing the region they drew.
% binaryMask is an image of Logical data type.
axes(handles.ImageViewer); % Switch current figure back to image box.
binaryMask = roipoly; % drop the binaryMask= and ; to see the binary image mask
imshow(binaryMask);
reply = questdlg({'Do you want to save the mask', 'to disk as a template?'},'Save image?', 'Yes','No', 'Yes');
% reply = '' for Upper right X, 'Yes' for Yes, 'No' for No.
%uiwait();
if strcmpi(reply, 'Yes')
[fileName, folder] = uiputfile([handles.maskFolder '\TFC_Mask.png'],'Save mask file name');
[folder, baseFileName, ext] = fileparts(fileName);
maskFileName = fullfile(handles.maskFolder, [baseFileName '.png']);
% Save the mask image for later recall if desired.
imwrite(binaryMask, maskFileName, 'png');
% Refresh the listbox of mask filenames.
% Load list of mask images in the app\masks folder.
handles=LoadMaskLists(handles);
end
% guidata(hObject, handles);
catch ME
errorMessage = sprintf('Error in function %s() at line %d.\n\nError Message:\n%s', ...
ME.stack(1).name, ME.stack(1).line, ME.message);
set(handles.txtInfo, 'String', errorMessage);
WarnUser(errorMessage);
end
Aline
Aline le 5 Sep 2014
Thank you for your continued help! I guess I still don't completely understand GUIs yet. I built the GUI with GUIDE, and since it suggested to use uiwait/uiresume, I did. Plus, when I tried it without, the figure opened and closed again without waiting for any user action. Is there another way to avoid that?
Anyway, I figured out, that if I call uiwait again in my pushbutton_callback, after calling impoly, the GUI works as it should. I still don't know why I had that problem, but as long as this works, I'm happy :)
BTW: Is it ok to post that as an answer? Please tell me if it's not something you should do, and I'll delete it again..
It all depends on where the uiwait()s and uiresume()s are. After the OpeningFcn(), GUIDE will put this:
% UIWAIT makes untitled wait for user response (see UIRESUME)
% uiwait(handles.figure1);
It's commented out. In my apps I don't see it so I think I must usually delete it since it's not needed. Did you uncomment it?
Aline
Aline le 5 Sep 2014
Yes, I uncommented it there, and put uiresume in the "OK" pushbutton callback, so that it would resume (and go to the output function as far as I understood) once the button was clicked.
I would not do that. It should work fine without doing any of that.
Aline
Aline le 5 Sep 2014
OK. So you would just close the figure with the OK button press? But when would the Output Fcn run then? Do I need to put all the code I have in there into the button_callback then?
I suggest you put lines in like this to every function to see when they get run:
fprintf('Now entering blahblahblah()...\n')
% code for blahblahblah()
fprintf('Now leaving blahblahblah()...\n')
You'll see the OutputFcn() gets run both on startup and shutdown. I usually have a button called btnExit, but you can call it OK if that's what you want. When the user clicks it, this is the code that runs to shutdown the GUI:
%=====================================================
% --- Executes on button press in btnExit.
function btnExit_Callback(hObject, eventdata, handles)
% hObject handle to btnExit (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
try
fprintf(1, 'Just entered btnExit_Callback...\n');
fprintf('Saving settings and parameters...');
SaveUserSettings(handles, 1);
% Get rid of variables from the global workspace so that they aren't
% hanging around the next time we try to run this m-file.
clear global;
% Cause it to shutdown.
delete(handles.figMainWindow);
fprintf(1, 'Leaving btnExit_Callback.\n');
catch ME
errorMessage = sprintf('Error in function btnExit_Callback.\nError Message:\n%s', ME.message);
WarnUser(errorMessage);
end
SaveUserSettings() is a custom written routine where I save the state of all controls on the GUI (checkbox states, scroll bar values, etc.). WarnUser is simply this:
%======================================================
% Warn user via the command window and a popup message.
function WarnUser(warningMessage)
fprintf(1, '%s\n', warningMessage);
uiwait(warndlg(warningMessage));
return; % from WarnUser()

Connectez-vous pour commenter.

I finally figured out, that if I call uiwait again in my pushbutton_callback, after calling impoly, the GUI works as it should. I still don't know why I had that problem, but it works now :)
Just for sake of completeness, this is my code (the changed part from GUIDE):
Opening Function:
% --- Executes just before DrawPolygon is made visible.
function DrawPolygon_OpeningFcn(hObject, eventdata, handles, Img)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to DrawPolygon (see VARARGIN)
% Adjust image contrast
Img = imadjust(mat2gray(Img));
% Display Image in the figure's axes
imshow(Img,'Parent',handles.axes);
% Create handles object to pass along the functions and save the output
% The output will be the structure S with the user-created polygons.
handles.S = struct('Handle',{},'Polygon',{});
% Making the toolbar and menubar of the figure visible, so that amongst
% others zoom is enabled.
set(handles.figure1,'toolbar','figure');
set(handles.figure1,'menubar','figure');
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes DrawPolygon wait for user response (see UIRESUME)
uiwait(handles.figure1);
Output Function
% --- Outputs from this function are returned to the command line.
function varargout = DrawPolygon_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
for ii = 1:size(handles.S,2)
handles.S(ii).Polygon = getPosition(handles.S(ii).Handle);
% Should the endpoint of the polygon not be the startpoint, the polygon
% is not closed and problems arise later in the script.
if handles.S(ii).Polygon(end,:) ~= handles.S(ii).Polygon(1,:)
handles.S(ii).Polygon(end+1,:) = handles.S(ii).Polygon(1,:);
end
end
varargout{1} = handles.S;
% After output has been relayed, the figure can be closed and deleted
delete(handles.figure1);
Pushbutton Callbacks New Polygon
% --- Executes on button press in pushbutton_New.
function pushbutton_New_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton_New (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% If the 'New'
button is pressed, the user can start creating a new polygon
% in the image.
% The handle to the new polygon is saved in the handles.S structure. The
% structure is initially empty. A new element is added for each polygon
% created.
handles.S(size(handles.S,2)+1).Handle=impoly(handles.axes);
% Update handles structure
guidata(hObject, handles);
% Since impoly seems to break uiwait, it is called again.
uiwait(handles.figure1);
OK Button (jumps to output function)
% --- Executes on button press in pushbutton_OK.
function pushbutton_OK_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton_OK (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
uiresume(handles.figure1);
Jan
Jan le 19 Oct 2014

0 votes

I recently experienced a very similar problem: The callback function of a button drawed several ROIs from memory using imellipse . Thereafter, a uiwait(f) was called for the user to corrigate these ROIs. However, this uiwait(f) did not work.
Solution: call uiwait twice, like you did. Alternatively, You can call pause(0.001) before calling uiwait (once).
I did not got to the root of this problem, but this worked for me. Apperently there are indeed some problems when combining imroi functions and uiwait.
user001
user001 le 20 Déc 2016
Modifié(e) : user001 le 20 Déc 2016

0 votes

I too experienced the same problem (in R2014b) and found that re-calling `uiwait` in the `impoly`-containing callback function was necessary. Would be interested to know the reason the original `uiwait` is neglected in this case.

Question posée :

le 28 Août 2014

Modifié(e) :

le 20 Déc 2016

Community Treasure Hunt

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

Start Hunting!

Translated by