# Find the orientation of each arbitrary object in an image

50 views (last 30 days)
Torkan on 18 Oct 2019
Answered: Image Analyst on 18 Oct 2019
Hi,
I have an image like this? Does anybody have any idea how can I get the orientation of each object? I know that the objects are not suitable to assign any orientation but at least I learn how can I do that? Actually, I also want to remove some of the objects which have a strange shape.
Thanks

Adam Danz on 18 Oct 2019
Edited: Adam Danz on 18 Oct 2019
I used this question to practice some of my image processing skills (still in early stages of exploration).
Here's what I did step-by-step to compute the orientation of each object and to compute the linear equation of the major axis of each object.
I downloaded the image and named it 'bwimage.png' (also attached, same image). The result is shown in a figure below where the major axis of each object is drawn through its center point (and extended a bit).
% Is the image binary?
info = imfinfo('bwimage.png'); %including the pull path is better
info.BitDepth %ans = 24; so it's not a binary image.
I = imread('bwimage.png'); %including the pull path is better
% Convert RGB --> grayscale --> binary
BW = imbinarize(rgb2gray(I));
% Get rid of white border
BWConv = bwconvhull(~BW);
BW = BW & BWConv;
% Checkout the image to make sure the conversion made sense.
% Keep the figure because we'll add to it later
% Note the orientation of the y axis (reversed)
figure()
h = imshow(BW);
axis on
% Get the center coordinate for each object, it's orientation [-90:90 deg],
% and the lenght of its major axis (in pixels).
stats = regionprops('table',BW,'Centroid','MajorAxisLength','Orientation'
% How many objects were detected?
nObjects = size(stats,1); % = 74
% take a look at the results
% Continuing with the figure created above, add the center points
hold on
ph1 = plot(stats.Centroid(:,1), stats.Centroid(:,2), 'rs');
% using orientation, compute slope and y-intercept of each major axis
% Note the reversal of the sign of the orientation! This is to account
% for the reversed y axis!
% here---v
stats.Slope = atan(-stats.Orientation*pi/180);
% Compute y interceps
stats.Intercep = stats.Centroid(:,2) - stats.Slope.*stats.Centroid(:,1);
% Now that we've got the linear eq for each line, compute the bounds of each
% object along its major axis line. Add some extra length so we can see more of the lines.
% To use the exact major axis lenght, divide by 2 instead of 1.6 (both lines below)
stats.EndpointX = stats.Centroid(:,1) + [-1,1].* (stats.MajorAxisLength/1.6 .* sqrt(1./(1+stats.Slope.^2)));
stats.EndpointY = stats.Centroid(:,2) + [-1,1].* (stats.Slope .* stats.MajorAxisLength/1.6 .* sqrt(1./(1+stats.Slope.^2)));
% Plot major axis of each object that spans the length of the obj
mah = plot(stats.EndpointX.', stats.EndpointY.', 'r-')
The orientation of each object is stored in stats.Orientation. The slope and intercept of each major axis is stored in stats.Slope and stats.Intercept. The end points of each line segment draw is stored in stats.EndpointX/Y. And the center points of each object are stored in stats.Centroid.
Torkan on 18 Oct 2019
Edited: Torkan on 18 Oct 2019
Thank you so much. However, you change the number of objects I don't know why and how?!
Actually, you are right. You divide some of the objects to two or three. Maybe the continuity issue.
Adam Danz on 18 Oct 2019
Edited: Adam Danz on 18 Oct 2019
The number of objects is determined from within regionprops. You can read the documentaiton for that function to make adjustments to suit your needs.
Pay close attention to the tips section, especially,
"The function ismember is useful with regionprops, bwconncomp, and labelmatrix for creating a binary image containing only objects or regions that meet certain criteria."
and
"The functions bwlabel, bwlabeln, and bwconncomp all compute connected components for binary images."
You can modify my algorithm by using these different functions to isolate objects according to your needs.
ps, my recent update to my answer was just to improve some of the comments; none of the code was changed.

Guillaume on 18 Oct 2019
The structure (or table if you ask for table output) returned by regionprops has a field called 'Orientation' which is the angle of the major axis of an ellipse fitted to the object.
stats = regionprops(yourbwimage, 'Orientation');
Guillaume on 18 Oct 2019
If you want something else than an ellipse fit then you'll have to make the fit yourself. You can see how regionprop does it by looking at its code (edit regionprops make sure you don't modify it!).
I would say that for most of your shapes an ellipse fit would work for finding the orientation of the major axis.
Adam has made a nice demo for you using exactly this method, and it seems to work for all your shapes.
Torkan on 18 Oct 2019
Thank you so much
Yep it works, but the results are somewhat weird! Let's see what adams did!

Image Analyst on 18 Oct 2019
You can use regionprops to get shape info. One nice one is the circularity. If you want stick-like objects, you do
props = regionprops(binaryImage, 'Perimeter', 'Area', 'Orientation')
allAngles = [props.Orientation]; % Extract all orientation angles into one vector.
histogram(allAngles); % Show distribution of angles.
allAreas = [props.Area]; % Extract all areas into one vector.
allPerimeters = [props.Perimeter]; % Extract all perimeters into one vector.
circularities = allPerimeters .^ 2 ./ (4 * pi * allAreas);
Circular blobs will be close to 1 and tortuous-shaped blobs or stick-shaped blobs will have higher circularity values, like 5 or 10 or more.