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

Antworten (2)

Matt J
Matt J vor etwa 20 Stunden
Bearbeitet: Matt J vor etwa 20 Stunden

0 Stimmen

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 Kommentare

Daniel
Daniel vor etwa 8 Stunden
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
Matt J
Matt J vor etwa 7 Stunden
It should work if its anywhere on your Matlab path, but I wouldn't recommend adding things to built-in toolbox folders.

Melden Sie sich an, um zu kommentieren.

Image Analyst
Image Analyst vor etwa 2 Stunden

0 Stimmen

Yeah, of course. You can't use things like aspect ratio, area, etc. to classify shapes. Aspect ratio of a rectangle will change as you rotate it. And the shapes, in general, could be of any size and you need to account for that unless you know for a fact that all your test shapes will have the same orientation and size and only the location could be different.
A more robust way to detect simple shapes like yours is to count the number of vertices. See my attached demos.

Kategorien

Gefragt:

am 23 Mär. 2026 um 18:17

Beantwortet:

vor etwa 2 Stunden

Community Treasure Hunt

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

Start Hunting!

Translated by