Matlab GUI: Problems while using imfreehand() - matlab

I have applied Canny edge detection on am image and now want to crop a part of it for further procession. I have created 4 axes with the tags axes1, axes2, axes3 and axes4. I want to display the image first in axes1, then the edge detected again in axes1. Finally the cropped image is to be displayed in axes3 and the image after removal of holes in axes4.
I am including a sample code which recreates the problem:
function varargout = samp_GUI(varargin)
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, 'gui_Singleton', gui_Singleton, 'gui_OpeningFcn', #samp_GUI_OpeningFcn, 'gui_OutputFcn', #samp_GUI_OutputFcn, 'gui_LayoutFcn', [] , 'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before samp_GUI is made visible.
function samp_GUI_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
guidata(hObject, handles);
% --- Outputs from this function are returned to the command line.
function varargout = samp_GUI_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
% --- Executes on button press in browse.
function browse_Callback(hObject, eventdata, handles)
[filename pathname] = uigetfile({'*.jpg';'*.bmp'},'File Selector');
handles.myImage = strcat(pathname, filename);
axes(handles.axes1);
imshow(handles.myImage)
im=imread(handles.myImage);
bw3=im2bw(im,0.3); %threshold value taken as 0.3
BW3=edge(bw3,'canny');
edge_im = BW3;
axes(handles.axes1);
imshow(BW3);
h=imfreehand(handles.axes1);
M=~h.createMask();
I(M) = 0;
axes(handles.axes2);
imshow(I);title('Cropped Image')
I = bwareaopen(I, 50);
axes(handles.axes3);
imshow(I),title('Removed Holes');
% save the updated handles object
guidata(hObject,handles);
When i execute the code in a .m file, it runs perfectly with different images opening in different windows but when the same code is run for the GUI, blank images are problems. I do not seem understand where the problem lies.

I think that you're suffering from some form of copy/paste issue. If you look at the line in your code where I(M) = 0 this doesn't really make sense (given your example) since I is not defined.
MATLAB will not throw any errors at this point though, because it's perfectly valid to create a matrix in this way; however, doing so actually produces a row vector rather than the image you're wanting.
>> M = logical(eye(100));
>> size(M)
ans =
100 100
>> clear I
>> I(M) = 0;
>> size(I)
ans =
1 10000
I imagine what you wanted to do was to apply the mask to your image (im) in which case you should get what you want. I have provided an example below (not sure what you're trying to display in axes1).
load mri
img = double(D(:,:,12));
im = img ./ max(img(:));
figure
handles.axes1 = subplot(2,2,1);
handles.axes2 = subplot(2,2,2);
handles.axes3 = subplot(2,2,3);
handles.axes4 = subplot(2,2,4);
bw3=im2bw(im,0.3); %threshold value taken as 0.3
BW3=edge(bw3,'canny');
edge_im = BW3;
axes(handles.axes1);
imshow(BW3);
h=imfreehand(handles.axes1);
M=~h.createMask();
% Assign im to I to ensure proper cropping.
I = im;
I(M) = 0;
axes(handles.axes3);
imshow(I);title('Cropped Image')
M_noholes = bwareaopen(M, 50);
I(M_noholes) = 0;
axes(handles.axes4);
imshow(I),title('Removed Holes');
If you provide more information it will be easier to help you figure out what you need.

Related

MATLAB: How to store clicked coordinates (peakpoints) continuosly from time series plot even after panning etc.

I am currently working on a matlab GUI where I need to click unwanted peak points (not to delete them) and store their results in a matrix (continuously). I am using a pushbutton with the following code to collect the points and store results. However, when I clicked the points only the last clicked results stores (not all the clicked points). Also, since it is a continuous plot I am using a PAN pushbutton to move the data. Hence, I would like to do the following:
1)For a pushbutton click (to collect peaks from getpts function) I want to click and collect several points (store and append the values continuously for each click). Also, I want the array to be active even after I use the PAN button to move the plot.
2) I want to create another pushbutton to end the task (asking the user to "do you want to stop collecting the peak points", stop collecting the points and store the entire clicked results in an array)
axes(handles.axes1);
[ptsx1,ptsy1] = getpts(gcf);
idx = knnsearch([t',fbsum],[ptsx1 ptsy1],'k',1)
if evalin('caller', 'exist(''xArray'',''var'')')
xArray = evalin('caller','xArray');
else
xArray = [];
end
xArray = [xArray; idx] %
assignin('caller','xArray',xArray); `% save to base`
save('xArray.mat','xArray');
Sorry, this is my first post and please accept my apology and please clarify if something is not clear. Thanks in advance.
EDIT: Using a GUIDE based GUI Instead
In Matlab command window define your X & Y
>> x = 0:.1:4*pi;
>> y = sin(x);
>> y(10:10:end) = 2; %With some bad points to mark
Then run the GUI, select Start Marking, mark some points Pan around etc.:
>> plotTest(x,y)
After exiting the GUI look at the globla IDX_STORE:
>> global IDX_STORE
>> IDX_STORE
IDX_STORE =
10 30 40
If you want the x , y values marked then it is just
>> markedX = x(IDX_STORE);
>> markedY = y(IDX_STORE);
The GUI is laid out Like this picture.
GUI Code Looks like this:
function varargout = plotTest(varargin)
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',mfilename,'gui_Singleton',gui_Singleton,'gui_OpeningFcn', #plotTest_OpeningFcn, ...
'gui_OutputFcn', #plotTest_OutputFcn,'gui_LayoutFcn',[] ,'gui_Callback',[]);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before plotTest is made visible.
function plotTest_OpeningFcn(hObject, eventdata, handles, varargin)
global IDX_STORE
IDX_STORE = [];
handles.output = [];
if numel(varargin) ~= 2
handles.closeFigure = true;
else
x = varargin{1}; y =varargin{2};
handles.l = plot(handles.axes1,x,y);
hold(handles.axes1,'on')
handles.axes1.ButtonDownFcn = {#clickCallback,handles};
handles.l.ButtonDownFcn = {#clickCallback,handles};
guidata(hObject, handles);
end
% --- Outputs from this function are returned to the command line.
function varargout = plotTest_OutputFcn(hObject, eventdata, handles)
varargout{1} = [];
if (isfield(handles,'closeFigure') && handles.closeFigure)
errordlg('Nothing Passed in!')
end
% --- Executes on button press in markToggle.
function markToggle_Callback(hObject, eventdata, handles)
switch handles.markToggle.Value
case 1
handles.markToggle.String = 'Stop Marking';
case 0
handles.markToggle.String = 'Start Marking';
end
function clickCallback(hObj,evtData,handles)
global IDX_STORE
if handles.markToggle.Value == 0
return %Do Nothing if toggle not pressed.
end
coordinates = handles.axes1.CurrentPoint(1,1:2); %Get coordinates of mouse click
idx = knnsearch([handles.l.XData' handles.l.YData'],coordinates);%Find closest point in line data
IDX_STORE = unique([IDX_STORE idx]); %Store the index.
mH = findobj(handles.axes1,'tag','markLine');%Add some markers to see what you are doing.
if isempty(mH) %Make the marker plot if it doesn't exist
plot(handles.axes1, handles.l.XData(IDX_STORE),handles.l.YData(IDX_STORE),'rO','tag','markLine')
else%If it does exist then update the markers
mH.XData = handles.l.XData(IDX_STORE); mH.YData = handles.l.YData(IDX_STORE);
end
guidata(hObj,handles); %Save handles structure

GUIDATA updating "handles" in GUIDE with nested functions

I have a simple GUIDE with 2 push buttons:
Button #1 plots a sine graph.
Button #2 adds a "movable" vertical line to the graph.
Everything works fine and I can drag vertical line as desired.
What I'm trying to do now is to record x-position of vertical line (x_history) as I move it and save this x_history to the handles (via guidata) such that if I stop moving the line (mouse-up) and then resume moving the line (mouse-down and mouse-move) I can restore previous x_history from handles (via guidata).
The problem I'm facing is that every time go mouse-up the handles resets(!) the x_history field (removes the field), so I loose the previous record of x_history when I resume mouse-down and move the line.
What am I missing here?
PS: I found these posts relevant but not exactly applicable to my case given the presence of nested functions.
Post 1
Post 2
Post 3
Thanks,
Alborz
Here is the code:
function varargout = plot_test(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', #plot_vertline_handles_OpeningFcn, ...
'gui_OutputFcn', #plot_vertline_handles_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
end
function plot_vertline_handles_OpeningFcn(hObject,~,handles,varargin)
handles.output = hObject;
guidata(hObject, handles);
end
function varargout = plot_vertline_handles_OutputFcn(~,~,handles)
varargout{1} = handles.output;
end
%% Vertline Callback
function pushbutton_vertline_Callback(hObject,~,handles) %#ok<*DEFNU>
axis_h = handles.axis_h;
vertline_h = line('parent',axis_h,'xdata',[1 1],'ydata',[-1 1],...
'ButtonDownFcn', #mouseDown );
handles.vertline_h = vertline_h;
guidata(hObject,handles)
function mouseDown(~,~)
mousedown = true;
handles.mousedown = mousedown;
guidata(hObject,handles)
end
end
%% Plot Callback
function pushbutton_plot_Callback(hObject,~,handles)
clc;
open_figs_h = get(0,'children');
close(open_figs_h(2:end));
x = -pi:0.01:pi;
y = sin(x);
fig_h = figure('units','normalized','outerposition',[0.2 0.2 .5 .5],...
'WindowButtonMotionFcn', #MouseMove, 'WindowButtonUpFcn', #MouseUp );
axis_h = axes('parent',fig_h,'position',[0.1 0.1 .8 .8]);
line('parent',axis_h,'xdata',x,'ydata',y);
handles.axis_h = axis_h;
guidata(hObject,handles);
function MouseUp(~,~)
handles = guidata(hObject);
handles.mousedown = 0;
guidata(hObject,handles);
end
function MouseMove(~,~)
try handles = guidata(hObject);catch, end
if isfield(handles,'mousedown')
mousedown = handles.mousedown;
else
mousedown = 0;
end
if mousedown
x_current = get(axis_h,'CurrentPoint' );
vertline_h = handles.vertline_h;
set (vertline_h, 'XData',[x_current(1,1) x_current(1,1)] );
if isfield(handles,'x_history')
disp('Field "x_history" Exists in handles')
handles.x_history = [handles.x_history x_current(1,1)]
else
disp('Field "x_history" Does Not Exist in handles')
handles.x_history = x_current(1,1)
end
guidata(hObject,handles);
end
end
end
With Jan Simon's guideline, I figured what was missing in the code:
In the mouseDown callback (the nested function in pushbutton_vertline_Callback), I was missing to get the updated copy of handles. So, I needed to add this line to that nested function:
handles = guidata(hObject);

How to detect the area of the Ellipse using imellipse in MATLAB

I would be very grateful If anyone could help me to solve this problem.
Initially an Image to be loaded to the MATLAB. Image must contain an oval or circular shape object. I choose and draw the circle/ellipse there.
I have completed the above mentioned job. I have attached the MATLAB code and for figure just get full mooon image or egg for ellipse.
Now I want to calculate the area of that ellipse. Anybody there to sort me out from this situation.
Thank you
Here is the Code
function varargout = stack_overflow(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', #stack_overflow_OpeningFcn, ...
'gui_OutputFcn', #stack_overflow_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
%%
function stack_overflow_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
guidata(hObject, handles);
%%
function varargout = stack_overflow_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
%%
function load_image_Callback(hObject, eventdata, handles)
axes(handles.view);
global im
[path, user_cancel] = imgetfile();
if user_cancel
msgbox(sprintf('Error !!! \n Please upload the image'),'Error','Error');
return
end
im = imread(path);
imshow(im);
%%
function draw_circle_Callback(hObject, eventdata, handles)
axes(handles.view);
global temp;
global fcn;
temp = imellipse(gca, []);
fcn = makeConstrainToRectFcn('imellipse',get(gca,'XLim'),get(gca,'YLim'));
setPositionConstraintFcn(temp,fcn);
%%
function result_Callback(hObject, eventdata, handles)
%%
function result_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
You could use the createMask method of the imroi class to create a logical mask with the ellipse just drawn, and then sum all the pixels whose value is 1 (or 0...) in order to get the area. You can add something like this in your draw_circle_Callback:
Simple example which you can modify to adapt with your current code:
%// Create dummy image with logical false values.
Im = false(500,500);
imshow(Im);
hold on
%// Draw ellipse
hEllipse = imellipse
%// Create a logical mask
roi = createMask(hEllipse);
%// Sum the values equal to 1;
Area = sum(roi(:))

how to send data from a function out GUI matlab to function GUI.m

How can I pass values (x_locate, y_locate) for a static text in my GUI?
Because the function is out functions generated by the GUI. I'm not achieving to configure the set() function.
I believe it is using handles, but I've tried everything and failed.
to simplify I rewrote the code:
![enter image description here][1]
The "Locations.fig" have: 1 axes, 1 pushbutton and 2 static text.
ctrl+C
function varargout = Locations(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', #Locations_OpeningFcn, ...
'gui_OutputFcn', #Locations_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
function Locations_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
guidata(hObject, handles);
function varargout = Locations_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
function pushbutton1_Callback(hObject, eventdata, handles)
cla(handles.axes1,'reset');
axes(handles.axes1);
image = imread('eight.tif');
im = imagesc(image);
set(im,'ButtonDownFcn', #clique);
function clique (gcbo,eventdata,handles)
pos = get(gca, 'currentpoint');
x_locate = round(pos(1))
y_locate = round(pos(3)) % until here working!!!
set(handles.text1, 'string', ['x loc:' num2str(x_locate)]); %don´t working
set(handles.text2, 'string', ['y loc:' num2str(y_locate)]); %don´t working
Only callbacks set through GUIDE (or some other custom means) receive the extra handles argument. Otherwise, you'll need to retrieve the handles structure manually within the clique function:
handles = guidata(<object>);
The question of what <object> is depends on your GUI setup. If im is a child of the GUI figure, then gcbo1 will do. If it's in a separate figure, then you'll need to get a handle to the GUI figure. Using findobj to either enumerate all figures or search for some specific property of your GUI figure is the straightforward way to do it.
For example, all Handle Graphics objects have a 'Tag' property that you are free to use, which would be helpful in this case. In GUIDE, set the Tag property on your GUI figure to 'my GUI', then you can retrieve the data from anywhere like so:
hfig = findobj('Tag','my GUI');
handles = guidata(hfig);
[1] Incidentally, giving variables the same name as built-in functions isn't a great idea
Set the ButtonDownFcn to be:
set(im, 'ButtonDownFcn', #(src,evt)clique(src,evt,handles))
The Notlikethat resolved the problem! Thanks!!!
so:
x_locate = round(pos(1));
y_locate = round(pos(3)); % until here working!!!
hfig1 = findobj('Tag','text1');
handles = guidata(hfig1);
hfig2 = findobj('tag','text2');
handles = guidata(hfig2);
set(handles.text1, 'string', ['x loc:' num2str(x_locate)]);
set(handles.text2, 'string', ['y loc:' num2str(y_locate)]);
finalized

Import figures to MATLAB GUI using handles?

How can I literally take these figures and place them in the axes windows of my GUI?
I am not sure where to place handles in my user-defined code in the example below. I have 4 figures in total which look similar to this example. I want the 4 figures to be displayed in my GUI window and not in separate windows, so i've created 4 axes windows in the .fig file.
The code for this particular figure draws a grid of 66 black and white rectangles based on whether or not a value in MyVariable is a 1 or a 0. Black if MyVariable is a 1, White if MyVariable is 0. I have a file for my .fig GUI, one file to control the GUI and one with user-defined code that links to the GUI.
function test = MyScript(handles)
lots of code in between
% Initialize and clear plot window
figure(2); clf;
% Plot the west wall array panels depending on whether or not they are
% shaded or unshaded
for x = 1:11
for y = 1:6
if (MyVariable(x,y) == 1)
rectangle('position', [x-1, y-1, 1, 1] ,'EdgeColor', 'w', 'facecolor', 'k')
else if(MyVariable(x,y) == 0)
rectangle('position', [x-1, y-1, 1, 1], 'facecolor', 'w')
end
end
end
end
title('West Wall Array',...
'FontWeight','bold')
axis off
The figure for the above code looks like this:
The function definition contains all of my script code for all 4 plots because I didn't partition my script into individual functions earlier on.
My GUI script code contains:
MyScript(handles);
As DMR sais, it's necesary to set the 'CurrentAxes'. For example, if you want to plot into the axis with the tag name 'axis1' you should simply add:
axes(handles.axes1);
to your code. Below is a very simple example for a figure containing a 'axis1' and 'axis2' using your code (corrected) code from above. Im not really shure wether you want to plot on an axis on your gui itself or a separate figure. I hope I covered both cases.
function varargout = Test(varargin)
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', #Test_OpeningFcn, ...
'gui_OutputFcn', #Test_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before Test is made visible.
function Test_OpeningFcn(hObject, eventdata, handles, varargin)
% Choose default command line output for Test
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
plot(handles.axes2,-2*pi:0.1:2*pi,sin(-2*pi:0.1:2*pi));
% Initialize and clear plot window
MyVariable = ones(11,6);
MyVariable(1:5,1) = 0;
axes(handles.axes1);
for x = 1:11
for y = 1:6
if (MyVariable(x,y) == 1)
rectangle('position', [x-1, y-1, 1, 1] ,'EdgeColor', 'w', 'facecolor', 'k');
elseif(MyVariable(x,y) == 0)
rectangle('position', [x-1, y-1, 1, 1], 'facecolor', 'w');
end
end
end
title('West Wall Array',...
'FontWeight','bold')
figure(2); clf;
for x = 1:11
for y = 1:6
if (MyVariable(x,y) == 1)
rectangle('position', [x-1, y-1, 1, 1] ,'EdgeColor', 'w', 'facecolor', 'k');
elseif(MyVariable(x,y) == 0)
rectangle('position', [x-1, y-1, 1, 1], 'facecolor', 'w');
end
end
end
title('West Wall Array',...
'FontWeight','bold')
function varargout = Test_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
Your guide GUI should look like this:
And your result like this:
You can set the axis to plot into prior each plot command by setting the 'CurrentAxes' property of the figure.
Within GUIDE, you can tag a given axis, for example: http://www.mathworks.com/help/matlab/creating_guis/gui-with-multiple-axes-guide.html . Then within your drawing code, indicate which axis should be plotted into via the 'set' function and 'CurrentAxes' property.
A simple example is below, though it doesn't use GUIDE, only basic subplot axis handles:
% plots in most recent axis by default (ax2)
fig = figure;
ax1 = subplot(1,2,1);
ax2 = subplot(1,2,2);
plot(rand(1,10));
% indicate that you want to plot in ax1 instead
fig = figure;
ax1 = subplot(1,2,1);
ax2 = subplot(1,2,2);
set(gcf, 'CurrentAxes', ax1);
plot(rand(1,10));