hobject issue with function

5 views (last 30 days)
Jason
Jason on 8 Jan 2019
Answered: Rik on 8 Jan 2019
Hello, I have a function (localThresholdnTiles) that I call in which I pass an image and the number of tiles I want to subdivide the image upto to perform my own binarize function on. When I run the contents of the function below under a pushbutton callback (using GUIDE), it all works fine.
However, when I call the fucntion from a pushbutton callback e.g
centroids=localThresholdnTiles(handles,4, 4, IM) %(Im has already been defined)
I get the error message.
BLOCKPROC encountered an error while evaluating the user-supplied function handle, FUN.
The cause of the error was:
Undefined function or variable 'hObject'.
function [centroids]=localThresholdnTiles(handles,xtiles, ytiles, image)
%local thresholding - splits image up into xtiles by y tiles
Image=double(image); %Force image to double precision
[rows,cols]=size(Image);
% Number of tiles or chunks you want it divide up into. (xtiles, ytiles)
nx=floor(cols/xtiles); ny=floor(rows/ytiles); %Numbers pixels per tile to maintain integer number of tiles
figure
imshow(Image)
%Use blockproc ro run "myOperation" on each tile.
Binary1=blockproc(Image,[nx, ny],@(x) myOperation(hObject, eventdata, handles, x.data))
  10 Comments
Adam
Adam on 8 Jan 2019
Edited: Adam on 8 Jan 2019
I assume in your example of the previous comment you intended to remove 'handles' as an argument to the function when you added 'f'?
How you design something depends on how reusable you want it to be, how robust, how fussy you want to be and a whole raft of other things. There's no one right answer (though plenty of wrong answers as well as multiple 'right' answers!) to how to design something.
If I am running an algorithm that may be run multiple times though I usually like it to be as general as possible in its usage - e.g. I would want to be able to call it from the command line with hard-coded inputs for paramaters (or inputs taken from variables in the current workspace similarly) .
In your latter case you limit your function's usefulness by making it so tightly coupled to your UI that it makes no sense for it to be external because anything that uses it would have to pass in a struct that contains fields 'popupmenu14', 'axes4' and 'checkbox22' that are of the correct type.
Instead passing in contents, hAxes (a handle to your axes) and val would make the function much more general purpose as these can now be gathered from anywhere by the calling code. Even better would probably be to pass in IM rather than hAxes since that is all you use the axes for. They can be passed in from existing variables or from this same GUI or from a totally different GUI that you may design. Also if you write tests for your algorithm then these tests can create data that can be used as inputs which cannot be done if it is required to be this big handles struct.
It is analagous to tight coupling vs loose coupling when doing object-oriented programming. Factoring algorithms out into separate functions is good, but if their inputs are so tightly linked to the UI that you factored them out from then all you have really done is make your original function look shorter by moving some code out that still cannot be used from any other place.
Jason
Jason on 8 Jan 2019
Edited: Jason on 8 Jan 2019
I assume in your example of the previous comment you intended to remove 'handles' as an argument to the function when you added 'f'? yes thats correct.
Many thanks for your and everyone elses comments.
I wish I could accept more than one answer. Adam has been very informative about my style but it was Rik who originally asked about the handles argument and if it was needed which led me to remove it and see my code work. (Sorry Adam)
Actually, I cannot see the "Accept this answer" for Rik?
Jason

Sign in to comment.

Accepted Answer

Rik
Rik on 8 Jan 2019
I'll post it as an answer so you can accept it.
The root cause of your problem is that your call in blocproc assumed that a handles variable would exist. Since that is neither the case nor needed, the functions can be modified to skip it. (I would also suggest changing your function name to something that describes its purpose, like ConvertToBinaryDouble)
function [centroids]=localThresholdnTiles(handles,xtiles, ytiles, image)
%local thresholding - splits image up into xtiles by y tiles
Image=double(image); %Get Image
[rows,cols]=size(Image);
% Number of tiles or chunks you want it divide up into. (xtiles, ytiles)
nx=floor(cols/xtiles); ny=floor(rows/ytiles); %Numbers pixels per tile to maintain integer number of tiles
Binary1=blockproc(Image,[nx, ny],@(x) myOperation(str2double(get(handles.editThreshn,'String')), x.data))
regmax = imregionalmax(Binary1);
s = regionprops(regmax,double(Image), 'WeightedCentroid','Area');
centroids = cat(1, s.WeightedCentroid);
areas=cat(1,s.Area)
centroids(:,3)=areas;
end
function [ix]=myOperation(f, tile)
%Create Binary Image
level=mean(tile(:))+f*std(tile(:));
ix=tile;
ix(ix<level)=0;
ix(ix>level)=1; %ix is now a binary image
%where f is defined outside the function via
%f=str2double(get(handles.editThreshn,'String'));
end

More Answers (0)

Community Treasure Hunt

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

Start Hunting!