%% Object Sort Order for bwlabel, bwconncomp, and regionprops
% Someone recently asked me about the order of objects found by the functions bwlabel, bwconncomp, and regionprops. In this binary image, for example, what accounts for the object order?
%
%
%
% The functions bwlabel and bwconncomp both scan for objects in the same direction. They look down each column, starting with the left-most column. This animation illustrates the search order:
%
%
%
% Because of this search procedure, the object order depends on the top, left-most pixel in each object. Specifically, the order is a lexicographic sort of (c,r) coordinates, where c and r are the column and row coordinates of the top, left-most pixel.
% If you pass a binary image to regionprops, the resulting object order is the same as for bwconncomp, and that is because regionprops calls bwconncomp under the hood.
% Sometimes, people who are working with images of text ask to change things so that the search proceeds along rows instead of columns. The motivation is to get the object order to be same as the order of characters on each line. (Assuming a left-to-right language, that is.) That generally doesn't work well, though. Consider this text fragment:
%
%
%
% With a row-wise search, the letter "b" would be found first, followed by "L" and then "t." This animation shows why that happens:
%
%
%
%
% If you want a different sort order, I recommend returning the regionprops output as a table, and then you can use sortrows. Here are a couple of examples.

url = "https://blogs.mathworks.com/steve/files/rice-bw-ul.png";
A = imread(url);
imshow(A)

%

props = regionprops("table",A,["Centroid" "Area"])

%
% You could sort the objects according to their centroids, first in the horizontal direction and then in the vertical direction.

props.Centroid_x = props.Centroid(:,1);
props.Centroid_y = props.Centroid(:,2);
props_by_row = sortrows(props,["Centroid_y" "Centroid_x"])

%

imshow(A)
for k = 1:height(props_by_row)
    x = props_by_row.Centroid_x(k);
    y = props_by_row.Centroid_y(k);
    text(x,y,string(k),Color = "yellow", BackgroundColor = "blue", FontSize = 16, ...
        FontWeight = "bold", HorizontalAlignment = "center",...
        VerticalAlignment = "middle");
end

%
% For another example, you could sort by area.

props_by_area = sortrows(props,"Area","descend")

%

imshow(A)
for k = 1:height(props_by_area)
    x = props_by_area.Centroid_x(k);
    y = props_by_area.Centroid_y(k);
    text(x,y,string(k),Color = "yellow", BackgroundColor = "blue", FontSize = 16, ...
        FontWeight = "bold", HorizontalAlignment = "center", ...
        VerticalAlignment = "middle");
end
title("Objects sorted by area (biggest to smallest)")