Help with syntax for a self-made function

Hi folks,
I have the following function defined in Matlab but am getting an error when running. The error and the code are below. May I please ask for help with debugging this?
Thanks in advance
function fields = populateFields(index, structure)
Area(index) = getfield(structure, 'Area');
MajorAxisLength(index) = getfield(structure, 'MajorAxisLength');
MinoeAxisLength(index) = getfield(structure, 'MinorAxisLength');
Eccentricity(index) = getfield(structure, 'Eccentricity');
Orientation(index) = getfield(structure, 'Orientation');
ConvexArea(index) = getfield(structure, 'ConvexArea');
Circularity(index) = getfield(structure, 'Circularity');
EquivDiameter(index) = getfield(structure, 'EquivDiameter');
Solidity(index) = getfield(structure, 'Solidity');
Extent(index) = getfield(structure, 'Extent');
Perimeter(index) = getfield(structure, 'Perimeter');
MaxFeretDiameter(index) = getfield(structure, 'MaxFeretDiameter');
MaxFeretAngle(index) = getfield(structure, 'MaxFeretAngle');
MinFeretDiameter(index) = getfield(structure, 'MinFeretDiameter');
MinFeretAngle(index) = getfield(structure, 'MinFeretAngle');
end
function call:
[matrix, numObjects] = bwlabel(mask1);
rg = regionprops(matrix, 'all');
fields = populateFields(1, rg);
The error:
Output argument "fields" (and maybe others) not assigned during call to "Threshold>populateFields".

 Accepted Answer

Simon Chan
Simon Chan on 12 Aug 2021
Edited: Simon Chan on 12 Aug 2021
You have not define your output variable 'fields' in your function, so nothing returns from the function

11 Comments

@Simon Chan thanks, may I please ask how to define the output such that all the data is returned?
It depends on how you would like to be the format and type of the output. Below is just an example which only returns the variable 'Area' and 'Perimeter' as a 1x2 matrix. I also change the variable name to 'output'.
function output = populateFields(index, structure)
Area(index) = getfield(structure, 'Area');
MajorAxisLength(index) = getfield(structure, 'MajorAxisLength');
MinoeAxisLength(index) = getfield(structure, 'MinorAxisLength');
Eccentricity(index) = getfield(structure, 'Eccentricity');
Orientation(index) = getfield(structure, 'Orientation');
ConvexArea(index) = getfield(structure, 'ConvexArea');
Circularity(index) = getfield(structure, 'Circularity');
EquivDiameter(index) = getfield(structure, 'EquivDiameter');
Solidity(index) = getfield(structure, 'Solidity');
Extent(index) = getfield(structure, 'Extent');
Perimeter(index) = getfield(structure, 'Perimeter');
MaxFeretDiameter(index) = getfield(structure, 'MaxFeretDiameter');
MaxFeretAngle(index) = getfield(structure, 'MaxFeretAngle');
MinFeretDiameter(index) = getfield(structure, 'MinFeretDiameter');
MinFeretAngle(index) = getfield(structure, 'MinFeretAngle');
%
output = [Area, Perimeter];
end
Stephen23
Stephen23 on 12 Aug 2021
Edited: Stephen23 on 12 Aug 2021
"... how to define the output such that all the data is returned?"
You could define all fifteen or so variables that you want as output arguments:
But fifteen positional arguments... ugh. That is just designing bugs into your code. Best avoided.
Ditto putting all of the data into one indexed (i.e. positional) array/matrix: you lose the fieldname meta-information.
What is the very good reason why you can't just access the data directly from the structure?
What are you actually trying to achieve?
Hi @Stephen Cobeldick, I'll try and explain the whole programme's purpose.
There are images of objects (~1500 images) which I am thresholding the background out of to get information on the shape of the object. The object colour and shape changes over the images, but also the background colour changes too. Therefore, I need to use different thresholds and techniques to get a mask for the object for different image. The idea, however, is that I have ~200 folders to threshold, each with ~1500 images, so doing this by hand isn't ideal. Hence, there are several conditions within the for loop where I switch from one threshold technique or level to another, depending on the value of the area of the thresholded object (a high difference bewteen the area of the i'th mask and the (i-1)th mask means I need to switch to the next thresholding technique). Therefore, at each image, I threshold the object/background, then measure the region properties to determine if the correct threshold has been used as well as to determine the properties of the region. I then want to store these properties into a variable. The reason I have outsourced the regionprops calls to a function is because I use the terms in the function several times during the programme.
Hope that helps.
@Simon Chan thanks for this, but it appears this doesn't work for me. I've followed your syntax and in the function call, I say
[area, perim] = ...
but it doesn't seem to work unfortunately. I need to build a matrix, cell or struct of the regionprops outputs for each iteration of the loop, so it needs to go into a variable like area(i)...
"...I then want to store these properties into a variable."
You explained that you need to loop over folders and files, and that you need to store data.
I asked why you cannot just use that structure.
So... what is stoping you from just using that structure? You could probably even use a non-scalar structure with as many elements as files you need to process. It would probably be much simpler.
"I need to build a matrix, cell or struct of the regionprops outputs for each iteration of the loop,"
If you used a non-scalar structure then you can do that trivially after the loop:
@Stephen Cobeldick thank you, this is highly informative and the answer I was looking for! apologies for not knowing beforehand, although if I'd known this, I wouldn't need to ask the question!
I'm still unclear on the syntax, however. For example, if I have a struct, RG, within my loop, which is defined as
RG = regionprops(mask1, 'all');
then will RG not be overwritten for each iteration of the loop? Or would you suggest
RG(i) = regionprops(mask1, 'all');
and then extract the specific properties of the struct outside the loop with:
Area = {RG.Area};
"...will RG not be overwritten for each iteration of the loop?"
Yes, which is why you should use indexing, much like you showed.
@Stephen Cobeldick thanks for this, but as I mentioned in my previous comment I still need to access the new elements of the structure within the loop. So i'th Area term, for example, is needed to determine which threshold function I need to correctly threshold the i'th image. It seems like this technique doesn't allow for that.
"It seems like this technique doesn't allow for that."
Here are two simple approaches you could use. Either use the same index
for k = ..
RG(k) = regionprops(mask1, 'all');
RG(k).Area
..
end
or a temporary variable:
for k = ..
tmp = regionprops(mask1, 'all');
tmp.Area
..
RG(k) = tmp;
end
What did you try?
@Stephen Cobeldick thanks for this! I tried the former, but run across this error when partway through the loop, and am not sure what's causing it...I tried defining the variable RG = zeros(numImages, 32) at the start but the error still occurs at the 465th value of i. Can I please ask you why this might be?
Unable to perform assignment because the left and right sides have a different number of elements.

Sign in to comment.

More Answers (0)

Categories

Find more on Scripts in Help Center and File Exchange

Products

Release

R2021a

Community Treasure Hunt

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

Start Hunting!