GUI - Error when trying to program the second slide bar for the upper limit for variable hue in image processing (lower limit succeeded)

I am trying to implement two sliders - one for the lower limit and one for the upper limit - for an image processing project I am doing myself. I am trying to seperate fruits from the background by using a range of the hue value. I succeeded to implement one slider, the one for the lower limit. However, when I add the code of the second slider for the upper limit unfortunately I get the following error:
Error using uicontrol
Incorrect number of input arguments
Can someone help me with it?
RGB_Image_Re = imread('42.jpg');
%Shifting color model
HSV_B = rgb2hsv(RGB_Image_Re);
%Color seperation
hImage = HSV_B(:, :, 1);
f = figure(1);
ax = axes('Parent',f,'position',[0.13 0.39 0.77 0.54]);
%Initial values
Hue_min = 0;
Hue_max = 1;
%Slider for the lower limit of hue
Hmin_Slider = uicontrol('Parent',f,'Style','slider','Position',[81,54,419,23],...
'value', Hue_min, 'min',0, 'max',0.5, 'Callback', @(es, ed)Slider(RGB_Image_Re, hImage, es.Value));
% % Add a text uicontrol to label the slider.
% txt_Hmin = uicontrol('Style','text',...
% 'unit','normalized',...
% 'position',[81,55,419,24],...
% 'String','Fitting Parameter "H_min"');
%Slider for the upper limit of hue
Hmax_Slider = uicontrol('Parent',f,'Style','slide','Position',[81,54.1,419,23],...
'value', Hue_max, 'min',0,51, 'max',1, 'Callback', @(es, ed)Slider(RGB_Image_Re, hImage, es.Value));
%
% % Add a text uicontrol to label the slider.
% txt_Hmax = uicontrol('Style','text',...
% 'unit','normalized',...
% 'position',[81,60,419,24],...
% 'String','Fitting Parameter "H_max"');
function Slider(RGB_Image_Re, hImage, Hue_min, Hue_max)
mask = (hImage >= Hue_min) & (hImage <= Hue_max);
% Create variable masked image (output) based on RGB image (input).
maskedRGBImage = RGB_Image_Re;
% Set background pixels (i.e. leaves, sky, logs) where the mask is false to
% black color [0,0,0]
maskedRGBImage(repmat(~mask,[1 1 3])) = 0;
imshow(maskedRGBImage);
title('Initial color seperation: fruit');
end

1 Comment

I have deleted the duplicate post as a comment on another thread. Please do not post your question in multiple places.

Sign in to comment.

 Accepted Answer

Your syntax doesn't match up. In your callback definition you have only 3 inputs, but your function assumes 4. I would suggest storing all handles and data in guidata and retrieving it in the callback.
You should also always use explicit handles to graphics objects. You also might consider using imshow only during initialisation, and then only setting the CData property of the image object it returns. That will be much faster.
h=struct; %put all handles and data in this struct
h.f=f;
%Slider for the lower limit of hue
h.min_Slider = uicontrol('Parent',f,'Style','slider', ...
'Units','Pixels','Position',[81,54,419,23],...
'value', Hue_min, 'min',0, 'max',0.5,...
'Callback', @Slider);
h.max_Slider = uicontrol('Parent',f,'Style','slider',...
... %this was missing an r
'Units','Pixels','Position',[81,54.1,419,23],...
'value', Hue_max, 'min',0.51, 'max',1,...
... %this was 0,51
'Callback', @Slider);
guidata(h,h.f)
function Slider(hObj,eventdata)
h=guidata(hObj);
RGB_Image_Re=h.RGB_Image_Re;
hImage=h.hImage;
Hue_minh.min_Slider.Value;
Hue_max=h.max_Slider.Value;
mask = (hImage >= Hue_min) & (hImage <= Hue_max);
% Create variable masked image (output) based on RGB image (input).
maskedRGBImage = RGB_Image_Re;
% Set background pixels (i.e. leaves, sky, logs) where the mask is false to
% black color [0,0,0]
maskedRGBImage(repmat(~mask,[1 1 3])) = 0;
imshow(maskedRGBImage,'Parent',h.ax);
title(h.ax,'Initial color seperation: fruit');
end

14 Comments

Thanks! It worked after placing the below two lines outside the function and the otherway around:
h.RGB_Image_Re = RGB_Image_Re;
h.hImage = hImage;
%AND
guidata(h.f, f)
Can you explain to me the following two comments of you ?:
- Always use explicit handles to graphics objects. Can you give an example?
-Use imshow only during initialisation, and then only setting the CData property of the image object it returns. How could I do this? I am not familiar with this.
Moreover, how can I code that the lower limit slider can't be higher than the upper limit slider? I am also wondering what MATLAB does if for example: 0.50 <= x <= 0.12.
I showed in my answer what I mean: I used 'Parent',ax when calling imshow. That way you make sure that the image will show up where you expect it to be, even if the user clicked on other figures and axes.
If you use h_im=imshow(___); that will return the handle to an image object, just like f=figure; returns the handle to a figure object. You can set values to it, just like you can with the Value property of your sliders.
As for your last question you will need to change your setup to achieve that.
At the start of your callback function you should check if the two values are the correct way around. I would suggest setting the Userdata property of each slider:
h.min_Slider = uicontrol('Parent',f,'Style','slider', ...
'Userdata','min');
h.max_Slider = uicontrol('Parent',f,'Style','slider',...
'Userdata','min');
That way you can determine with hObj.Userdata which slider is currently changing. If this is your intention, you should probably set the min and max values to 0 and 1 for both. Currently the value of your min slider can't be above the value of the max slider.
As for 0.50 <= x <= 0.12: this is a common mathematical syntax, but it doesn't work like this in Matlab. You need 0.50 <= x && x <= 0.12 instead.
The first answer is clear. The second one not really. You mention: ''Use imshow() only during the initialization''.
Do you mean with that outside the function?
I have tried the following. I have put the following two lines outside the function and under the line h.ax = ...:
h.h_im = imshow(h.RGB_Image_Re,'Parent',h.ax);
title(h.ax,'Initial color seperation: fruit');
Within the function I have put:
set(h.h_im, 'CData', []);
However, the picture dissapears when I am using the slider.
Of course it disappears, you have set the image to an empty array. What did you expect to happen there? You should do set(h.h_im,'CData',maskedRGBImage) instead.
The code that starts you GUI should be in a function. That way it will not influence any other code. That function will only run once: when you start the GUI. So if you want things to happen only once (e.g. calling imshow) you can do it there. In that function you make sure to store all handles and data you need in the guidata struct.
I only showed it here as a script with an internal function for convenience and brevity.
Okay, I misunderstood the set() function. However, I am still quite confused about your function story, because most of the GUI problems online where in the format of script and internal function.
Do you suggest something like this? (it doesn't work yet, but more for my understanding, because I am doubting if this is what you meant)
%%Function file
function guidata = myGUI(hImage, RGB_Image_Re)
h=struct; %put all handles and data in this struct
h.RGB_Image_Re = RGB_Image_Re;
h.f = figure(1);
h.ax = axes('Parent',h.f,'position',[0.13 0.39 0.77 0.54]);
h.h_im = imshow(h.RGB_Image_Re,'Parent',h.ax);
title(h.ax,'Initial color seperation: fruit');
%Initial values
Hue_min = 0;
Hue_max = 1;
%Slider for the lower limit of hue
h.min_Slider = uicontrol('Parent',f,'Style','slider', ...
'Units','Pixels','Position',[81,54,419,23],...
'value', Hue_min, 'min',0, 'max',1,...
'Callback', @Slider);
h.max_Slider = uicontrol('Parent',f,'Style','slider',...
'Units','Pixels','Position',[81,54.1,419,23],...
'value', Hue_max, 'min',0, 'max',1,...
'Callback', @Slider);
guidata(h,h.f)
end
%%Main file
[guidata] = myGUI(hImage, RGB_Image_Re)
%Function file
function Slider(hObj,eventdata)
h=guidata(hObj);
Hue_minh.min_Slider.Value;
Hue_max=h.max_Slider.Value;
mask = (hImage >= Hue_min) & (hImage <= Hue_max);
% Create variable masked image (output) based on RGB image (input).
maskedRGBImage = RGB_Image_Re;
% Set background pixels (i.e. leaves, sky, logs) where the mask is false to
% black color [0,0,0]
maskedRGBImage(repmat(~mask,[1 1 3])) = 0;
set(h.h_im, 'CData', maskedRGBImage);
end
You shouldn't use guidata as an output variable, as it is a function. You can also put all these functions in a single file.
Other than that, yes, this is the general idea.
If my answer has helped you, please consider marking it as accepted answer.
For general advice and examples for how to create a GUI (and avoid using GUIDE), have look at this thread.
So, if I understand you correctly, you make besides the main script a function file with myGUI as the main function and Slider as the local function. However, what is the output then of myGUI , because in the main script I should call the function in order to perform the task.... I think I still don't grasp the idea and that's why I am still confused.
I have now this:
Main script
myGUI(hImage, RGB_Image_Re)
Function script
function [] = myGUI(hImage, RGB_Image_Re)
end
function Slider(hObj,~)
end
I get the following error:
Dot indexing is not supported for variables of this type.
Error in myGUI>Slider (line 49)
Hue_min = h.min_Slider.Value;
Error while evaluating UIControl Callback.
In general I don't make GUIs with output variables. However, you can use uiwait or waitfor in your main GUI function:
function output = myGUI(hImage, RGB_Image_Re)
% create the GUI
uicontrol(___)
guidata(h,h.f)
% Wait for the 'confirm' button.
uiwait(h.f);
% This allows user interaction with the GUI, but otherwise the execution of
% this function is paused.
h=guidata(h.f);%reload data
output= %the values of the sliders?
end
function Slider(hObj,~)
end
function ConfirmButtonCallback(hObj,~)
uiresume(gcbf) %gcbf is the parent figure of hObj
end
As for your error: you need to make sure to save all data you may need to the h struct, then store it to the figure with guidata. The important thing to remember is that guidata(h,h.f) will store the data, and h=guidata(___); will load the data.
The main idea of a GUI is that all functions related to the GUI itself are in a single m-file. That m-file should start with a function that creates your GUI (with calls to uicontrol etc). Any callback should probably be in that same file to make things clear. It is fine to only have a wrapper, but you probably need to pass specific variables (stored in guidata), so having the callback function there is probably best.
I would really encourage you to read the thread I linked. I have tried to make it as clear as I can there. You will also find many links to the documentation there. You're already most of the way there.
I read the thread and made it work, thanks. It seems to be much faster. Still two small questions.
1) If you use:
output = %the values of the sliders? --> It saves only the initial values and not the continuously changing values
I want to save the final image of h_im, mask, maskedRGBImage and the values of the slider. Shouldn't the this output come from the function Slider(hObj,~) as the most recent is needed?
2) At the same time I am showing the fruit, I want to show the background in another plot. I succeeded to make two seperate plot. However, I would like to have one figure with two subplots. Do you know how I can change the code accordingly?
h.f = figure(1);
h.ax = axes('Parent',h.f,'position',[0.13 0.39 0.77 0.54]);
h.h_im = imshow(h.RGB_Image_Re,'Parent',h.ax);
title(h.ax,'Initial color seperation: fruit');
h.g = figure(2);
h.ax2 = axes('Parent',h.g,'position',[0.13 0.39 0.77 0.54]);
h.h_im2 = imshow(h.RGB_Image_Re,'Parent',h.ax2);
title(h.ax2,'Initial color seperation: background');
1)
Because you should put that after the uiwait call, that should actually be the value when you press the confirm button. Since by that time you should already have done everything you need that requires updating values, that should no longer be an issue.
The callback doesn't have an output. It is h.min_Slider.Value that changes, so you can use that in your main GUI function.
2)
If you want two axes in the same figure, why did you create a second figure? Just put them side by side. You could use subplot, but you're already specifying the axes position explicitly, so you can just add it. Use h.f as the Parent for the second one and adapt the Position to make sure they don't overlap.
I already tried to simply use subplot:
h.f = figure(1);
subplot(1,2,1);
h.ax = axes('Parent',h.f,'position',[0.13 0.13 0.77 0.54]);
h.h_im = imshow(h.RGB_Image_Re,'Parent',h.ax);
title(h.ax,'Initial color seperation: fruit');
subplot(1,2,2);
h.ax2 = axes('Parent',h.f,'position',[0.95 1.21 0.77 0.54]);
h.h_im2 = imshow(h.RGB_Image_Re,'Parent',h.ax2);
title(h.ax2,'Background');
However, I get then the following error if I use the slider:
Error using matlab.graphics.primitive.Image/set
Invalid or deleted object.
Error in myGUI>Slider (line 91)
set(h.h_im, 'CData', maskedRGBImage);
Error while evaluating UIControl Callback.
subplot already creates the axes object. But since you already create the axes with your customized positions, you should simply remove the calls to subplot and leave the rest of your code.
I don't see what could delete the image object that imshow creates in your code. Maybe the second subplot call messed with that, although I can't really see why.
You need to make that confirmation button yourself.
If you would read the documentation you would see that the Position argument can be specified in several units, which is determined by the Unit property. In this case the default is Normalized, meaning that the x is in terms of the width of the parent object and the y is in terms of the height of the parent object.
Most of the follow-up issues so far seem to stem from the point that you don't seem to read the documentation for the functions you're using. If you start reading it yourself you don't have to wait for me to respond.
Yes, I understood the Position, otherwise I wouldn't succeed (at first I didn't understand, but when I read the documentation I succeeded). I think you misunderstood me. I removed that comment.
My main focus is not the GUI. That's why I got confused by the button. I only want the parameters as output.

Sign in to comment.

More Answers (1)

yes,sir,use Rik method,modify as
clc; clear all; close all;
RGB_Image_Re = imread('https://ww2.mathworks.cn/matlabcentral/answers/uploaded_files/816944/42.jpg');
%Shifting color model
HSV_B = rgb2hsv(RGB_Image_Re);
%Color seperation
hImage = HSV_B(:, :, 1);
f = figure(1);
ax = axes('Parent',f,'position',[0.13 0.39 0.77 0.54]);
% here use Rik method
h=struct; %put all handles and data in this struct
%Initial values
Hue_min = 0;
Hue_max = 1;
%Slider for the lower limit of hue
h.min_Slider = uicontrol('Parent',f,'Style','slider', ...
'Units','Pixels','Position',[81,54,419,23],...
'value', Hue_min, 'min',0, 'max',0.5);
h.max_Slider = uicontrol('Parent',f,'Style','slider',...
... %this was missing an r
'Units','Pixels','Position',[81,77,419,23],...
'value', Hue_max, 'min',0.51, 'max',1);
% here modify some code, not use guidata, just use h
set(h.min_Slider, 'Callback', @(es, ed)Slider(RGB_Image_Re, hImage, h));
set(h.max_Slider, 'Callback', @(es, ed)Slider(RGB_Image_Re, hImage, h));
function Slider(RGB_Image_Re, hImage, h)
Hue_min=h.min_Slider.Value;
Hue_max=h.max_Slider.Value;
mask = (hImage >= Hue_min) & (hImage <= Hue_max);
% Create variable masked image (output) based on RGB image (input).
maskedRGBImage = RGB_Image_Re;
% Set background pixels (i.e. leaves, sky, logs) where the mask is false to
% black color [0,0,0]
maskedRGBImage(repmat(mask,[1 1 3])) = 0;
imshow(maskedRGBImage);
title('Initial color seperation: fruit');
end

5 Comments

What is the point of this modification? What makes it different from my answer? I don't see why this couldn't be a comment on my answer. Can you explain that?
@Rik sorry,sir,it use your method,and not use
h.f = f;
guidata(h.f, f);
to just use as single script code,not use guidata to generate gui
because when use figure handle,it may be so complex
so,i made some modified code
sorry again
@S. please check and use Rik method,thank you
Your method seems to be less lines of code. Why you suggest to use Rick's method?
yes,sir,because I refer to some codes
anyway, If you can solve the problem, I wish you every success

Sign in to comment.

Asked:

S.
on 29 Nov 2021

Edited:

S.
on 2 Dec 2021

Community Treasure Hunt

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

Start Hunting!