% Identifying Objects From An Image - SOLUTION
% Using Image Processing Toolbox
% In MATLAB 2025

clc;
clear all;

function displayImage(image, name)
    figure,
    imshow(image, 'InitialMagnification', 'fit') % will fill window size
    title(name)
end

colored_image = imread("shapes.png");
displayImage(colored_image, "Original Image")

% PREPROCESS THE IMAGE
% Step 1: Convert to black and white

grayed = im2gray(colored_image); % turns all colors to shade of gray
bw = imbinarize(grayed);         % turns shade of gray to black or white
displayImage(bw, "Black and White Image")

% Step 2: remove unwanted pixels and fix empty space

minSize = 30;
bw = bwareaopen(bw, minSize);    % remove objects less than 30 pixels
displayImage(bw, "Filtered Image")

se = strel("disk", 2);
bw = imclose(bw, se);            % fill small gaps and holes
displayImage(bw, "Unfilled Fixed Image")

bw = imfill(bw, "holes");        % fill any holes in objects
displayImage(bw, "Filled Fixed Image")

% Step 3: find boundaries of the shapes
% in a binary image background is 0 and object is 1

[B, L] = bwboundaries(bw, "noholes");

hold off
labeled_image = label2rgb(L, @jet, [.5 .5 .5]);
displayImage(labeled_image, 'Objects with Boundaries in White')
hold on
for k = 1:length(B)
    boundary = B{k};
    plot(boundary(:,2), boundary(:,1), "w", LineWidth = 2)
end

% FIND SHAPES IN IMAGE
% Finds Circles, Triangles, and Squares
stats = regionprops(L, "Circularity", "Eccentricity", "Solidity", "Centroid");
% Circularity: how circular the object is, close to 1 for circle
% Eccentricity: how elongated a object is, range 0-1 with 0: circle 1: line
% Solidity: 
% Centroid: center point of the object
% Area: number of pixels in the object

threshold_circularity = 0.94;
threshold_eccentricity_triangle = 0.6;
threshold_solidity_square = 0.9;

for k = 1:length(B)
    boundary = B{k};
    circle_value = stats(k).Circularity;
    ecc_value = stats(k).Eccentricity;
    solidity_value = stats(k).Solidity;

    % Classify shapes based on properties
    if circle_value > threshold_circularity
        shape = "Circle";
    elseif ecc_value < threshold_eccentricity_triangle
        shape = "Triangle";
    elseif solidity_value > threshold_solidity_square 
        shape = "Rectangle";
    else
        shape = "Other";
    end

    % Display shape type
    centroid = stats(k).Centroid;
    text(boundary(1, 2)-35, boundary(1, 1)+13, shape, Color="y", FontSize=14, FontWeight="bold")
end

title("Identified Shapes")
