identifying shapes in image

Any help with identifying the shapes in this image. they are incorrectly identified due to their rotaion. this code works great on identifying shapes in other pictures but this one it fails.
%% ========================================================================
% IMAGE PREPROCESSING + WATERSHED SEGMENTATION + RBC SHAPE CLASSIFICATION
% ========================================================================
% --- Select Image ---
[filename, pathname] = uigetfile( ...
{'*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.bmp;*.gif', ...
'Image Files (*.jpg, *.jpeg, *.png, *.tif, *.tiff, *.bmp, *.gif)'; ...
'*.*','All Files (*.*)'}, ...
'Select an image');
if isequal(filename,0)
disp('No file selected.');
return;
end
imgPath = fullfile(pathname, filename);
img = imread(imgPath);
% Detect grayscale or RGB
isGray = is_image_grayscale(img);
figure('Name', filename, 'NumberTitle', 'off');
%% ========================================================================
% PATH A — GRAYSCALE IMAGE
% ========================================================================
if isGray
% Original
subplot(3,2,1); imshow(img); title('Loaded (Grayscale)');
% Ensure grayscale
GRAY = im2gray(img);
subplot(3,2,2); imshow(GRAY); title('Grayscale Image');
% Dilation (line)
se_line = strel("line",10,0);
dil1 = imdilate(GRAY, se_line);
subplot(3,2,3); imshow(dil1); title('1st Dilation');
% Dilation (disk)
se_disk2 = strel("disk",2);
dil2 = imdilate(dil1, se_disk2);
subplot(3,2,4); imshow(dil2); title('2nd Dilation');
% Erode
se_disk1 = strel("disk",1);
erode = imerode(dil2, se_disk1);
subplot(3,2,5); imshow(erode); title('Erosion');
% Binary
BW = imbinarize(erode, 25/255);
subplot(3,2,6); imshow(BW); title('Binary (Threshold 25)');
pause(2);
% Invert
BW_inv = ~BW;
subplot(3,2,6); imshow(BW_inv); title('Inverted Binary');
% ------------------ Watershed ------------------
figure;
D = -bwdist(BW);
subplot(3,2,1); imshow(D, []); title('Distance Transform');
mask = imextendedmin(D,2);
D2 = imimposemin(D,mask);
L = watershed(D2);
L(BW) = 0;
subplot(3,2,2); imshow(label2rgb(L,'jet','w','shuffle'));
title('Watershed Segmentation');
subplot(3,2,3); imshow(label2rgb(L,'jet',[0.5 0.5 0.5]));
title('Watershed Transform');
%% ========================================================================
% PATH B — RGB IMAGE
% ========================================================================
else
subplot(3,2,1); imshow(img); title('Loaded (Colour)');
% HSV saturation adjustment
HSV = rgb2hsv(img);
S = HSV(:,:,2);
gamma = 3;
S_tweaked = S.^gamma;
subplot(3,2,2); imshow(S_tweaked, []); title('Saturation (Gamma=3)');
% Convert to grayscale
GRAY = im2gray(S_tweaked);
subplot(3,2,3); imshow(GRAY); title('Grayscale');
% Morphological closing
se_close = strel("disk",10);
close_img = imclose(GRAY, se_close);
subplot(3,2,4); imshow(close_img); title('Close');
% Opening
se_open = strel("disk",3);
open_img = imopen(close_img, se_open);
subplot(3,2,5); imshow(open_img); title('Open');
% Binary image
BW = imbinarize(open_img);
subplot(3,2,6); imshow(BW); title('Binary');
pause(2);
BW_inv = ~BW;
subplot(3,2,6); imshow(BW_inv); title('Inverted Binary');
% ------------------ Watershed ------------------
figure;
D = -bwdist(~BW);
subplot(3,2,1); imshow(D,[]); title('Distance Transform');
mask = imextendedmin(D,2);
D2 = imimposemin(D,mask);
L = watershed(D2);
L(~BW) = 0;
subplot(3,2,2); imshow(label2rgb(L,'jet','w','shuffle'));
title('Watershed Segmentation');
subplot(3,2,3); imshow(label2rgb(L,'jet',[0.5 0.5 0.5]));
title('Watershed Transform');
end
%% ========================================================================
% SHAPE CLASSIFICATION (CIRCLE / TRIANGLE / SQUARE / RECTANGLE)
% ========================================================================
figure; imshow(img); hold on;
labels = unique(L);
labels(labels==0) = []; % remove background
for k = 1:length(labels)
regionMask = (L == labels(k));
% Stats
stats = regionprops(regionMask,'Area','Perimeter','BoundingBox','Centroid');
A = stats.Area;
P = stats.Perimeter;
BB = stats.BoundingBox;
C = stats.Centroid;
% RBC classification
shape = classifyPrimitive(A, P, BB);
% Put label on image
text(C(1), C(2), shape, ...
'Color', 'white', ...
'FontSize', 12, ...
'FontWeight', 'bold', ...
'HorizontalAlignment', 'center');
end
hold off;
%% ========================================================================
% FUNCTIONS
% ========================================================================
function tf = is_image_grayscale(I)
if ndims(I)==2
tf = true;
elseif ndims(I)==3 && size(I,3)==3
tf = isequal(I(:,:,1),I(:,:,2)) && isequal(I(:,:,1),I(:,:,3));
else
tf = false;
end
end
% --- RBC Primitive Classifier ---
function label = classifyPrimitive(area, perimeter, bbox)
w = bbox(3);
h = bbox(4);
%% Circle metric from RBC paper (should be ~1)
circle_metric = (perimeter^2) / (4*pi*area);
if abs(circle_metric - 1) < 0.158
label = 'Circle';
return;
end
%% Triangle metric: area approx half bounding box
bbox_area = w*h;
area_ratio = area / bbox_area;
if area_ratio > 0.30 && area_ratio < 0.65
label = 'Triangle';
return;
end
%% Square vs Rectangle
aspect_ratio = w/h;
if abs(aspect_ratio - 1) < 0.60
label = 'Square';
else
label = 'Rectangle';
end

Answers (1)

Matt J
Matt J about 13 hours ago
Edited: Matt J about 13 hours ago
See this FEX download,
load Image;
pgons=bwlpolyshape(~BW, Visualize=true);
shapes=arrayfun(@classify,pgons(:))
shapes = 8×1 string array
"Square" "Triangle" "Rectangle" "Rectangle" "Circle" "Square" "Triangle" "Square"
function shape=classify(pgon)
Lengths=vecnorm(diff(pgon.Vertices([end,1:end],:)),2,2); %Side lengths
Lengths(Lengths<max(Lengths)/20)=[]; %Tolerance on shortest side length
N=numel(Lengths); %Number of sides (after tolerance)
if N==3
shape="Triangle";
elseif N==4
shape="Rectangle";
if max(Lengths)-min(Lengths)<3 %Tolerance on side length equality
shape="Square";
end
elseif N>10
shape="Circle";
end
[cx,cy]=centroid(pgon);
drawpoint(Position=[cx,cy],Label=shape,LabelText="white");
end

2 Comments

im having trouble getting the bwlpolyshape to work, did you just add the downloaded code to the image toolbox codes in here C:\Program Files\MATLAB\R2025b\toolbox\images\images
It should work if its anywhere on your Matlab path, but I wouldn't recommend adding things to built-in toolbox folders.

Sign in to comment.

Categories

Asked:

about 18 hours ago

Commented:

about 1 hour ago

Community Treasure Hunt

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

Start Hunting!