how do i assign a color to the same type of shape
2 views (last 30 days)
Show older comments
Now that each shape is classified into its group, how would i go about to add color to each shape, each shape must be colored according to group i.e squares all blue, circles all red,but shape that don't fall into the classification should be black in color. I used RGB2 below but i cant add the shapes together into an image with a white background. Is there any other method???
RGB2 = label2rgb(L==n, 'copper', 'w', 'noshuffle');
eg. squares=blue
eg. circles=r
ed
Answers (3)
Doug Hull
on 12 Nov 2014
If you make this a binary image, you can run it through regionprops. There are a variety of metrics in there that should be usefull in identifying equal shapes. Without much more information, I think this will be enough to get you in the right direction.
Image Analyst
on 12 Nov 2014
Once you've identified the shapes, which we've talked about in your other question, you can use a for loop to reassign your labeled region to the desired number, like 1 for squares = blue, 2 for circles = red, and so on. Then just create the colormap and pass that plus the labeled image in to ind2rgb() to get an RGB image with shapes having the desired color.
DGM
on 14 Mar 2023
Edited: DGM
on 14 Mar 2023
It's no surprise OP got lost. That's an awful lot of duplicated code, unused code, and misleading variable names. I got lost.
This is an attempt to clean it up so that it runs at least as much as it did before. There are still a lot of things that could be simplified, fixed, or otherwise improved.
The code as given wouldn't run with the given image, since the edge detection generates a bunch of spurious blobs. That's probably because the input is a crusty JPG.
clearvars % clean up
close all
clc
fontsize = 8; % used for figure labels
textbgc = 'y';
RGB = imread('test_shapes.jpg'); %read the loaded image
sharp=imsharpen(RGB); %sharpen the read image
grayscale=rgb2gray(sharp); %convert from rgb image to grayscale format
h = fspecial('gaussian',40,1); %create a smoothing filter
filtered = imfilter(grayscale,h); %filtering
Edgecanny = edge(filtered,'canny'); %edge detection
X = imfill(Edgecanny,'holes'); %fill in with holes
% get rid of all the tiny blobs created by doing edge detection on a JPG
Bw = bwareaopen(X,1500);
% get the label image
[L numblobs] = bwlabel(Bw);
% define shape class names
shapeclasses = {'Circle','Square','Triangle','Rectangle','Pentagon', ...
'Hexagon','Ellipse','Octagon','Diamond','Unknown'};
% preallocate
blobcentroids = zeros(numblobs,2); % the [x y] centroid location for each blob
blobclasses = zeros(numblobs,1); % the class number for each blob
blobaream = zeros(numblobs,1); % the unrounded area for each blob (in sq m)
for n=1:numblobs
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SHAPE FACTORS
thisblobonly = L==n; % do it once instead of 14 times
[row, col] = find(thisblobonly);
% Find Bounding Box
sx = min(col)-0.5; %starting position for column
sy = min(row)-0.5; %starting position for row
breadth = max(col)-min(col)+1; %gives breadth of the box
length = max(row)-min(row)+1; %gives length of the box
BBox = [sx sy breadth length]; %Bounding Box value for the range of n
% Find area ratio
blobarea = bwarea(thisblobonly); %calculates the area of each binary component
blobaream(n) = round(blobarea) * 0.001; %converting from mm to m
bboxarea = (length*breadth); %calculates the area of each bounding box
extent = blobarea/bboxarea; %calculates the ratio of area's
fprintf('Extent: %.4f\n',extent)
% Find Perimeter
thisboundary = bwboundaries(thisblobonly); %Find the boundary of the labeled components boundary pixels
c = cell2mat(thisboundary(1)); %converts the cell to a matrix
Perimeter = 0; %declaring a start at zero for sum
for i = 1:size(c,1)-1 %creates a loop that extracts perimeter of each binary component
Perimeter = Perimeter+sqrt((c(i,1)-c(i+1,1)).^2+(c(i,2)-c(i+1,2)).^2);
end
fprintf('Perimeter: %.3f\n',Perimeter); %display perimeter
% Find Roundness
Roundness = (4*blobarea*pi)/Perimeter.^2; %defines how close the binary component is to a circle
fprintf('Roundness: %.3f\n',Roundness); %display roundness factor
% Find aspect ratio instead of distance between first three vertices
aspectratio = min(BBox(3:4))/max(BBox(3:4)); % normalized
fprintf('Aspect: %.3f\n',aspectratio);
% Find Centroid
X = mean(col); %calculates average of columns
Y = mean(row); %calculates average of rows
blobcentroids(n,:) = [X Y]; %matrix of centroid dimensions
fprintf('Centroid: [%d %d]\n',round(blobcentroids(n,:))); %display centroid
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SHAPE CLASSIFICATION
if extent>=0.782 && extent<=0.800 && Roundness>=0.909
blobclasses(n) = 1; % CIRCLE
elseif aspectratio>=0.9 && extent>=0.97
blobclasses(n) = 2; % SQUARE
elseif extent>=0.526 && extent<=0.550 && Roundness>=0.541 && Roundness<=0.559
blobclasses(n) = 3; % TRIANGLE
elseif aspectratio<0.9 && extent>=0.97
blobclasses(n) = 4; % RECTANGLE
elseif extent>=0.694 && extent<=0.714
blobclasses(n) = 5; % PENTAGON
elseif extent>=0.758 && extent<=0.769
blobclasses(n) = 6; % HEXAGON
elseif extent>=0.782 && extent<=0.800 && Roundness<0.909
blobclasses(n) = 7; % ELLIPSE
elseif extent>=0.833 && extent<=0.909
blobclasses(n) = 8; % OCTAGON
elseif extent>=0.526 && extent<=0.535 && Roundness>=0.714 && Roundness<=0.769
blobclasses(n) = 9; % DIAMOND
else
blobclasses(n) = 10; % NOT CLASSIFIED SHAPE
end
% dump another message into the console
fprintf('Blob %d is a %s\n\n',n,lower(shapeclasses{blobclasses(n)}));
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% create a bunch of subplots
% doing the junk with blind axes position manipulation is a nightmare
% it's entirely dependent on the relationship between the aspect ratio of the figure window
% and the aspect ratio of the images.
% there's no reason to expect that the titles will even be visible.
% the modern suggestion would be to use tiledlayout, but that wasn't an option in 2014.
% FEX subplot_tight() would have probably been sufficient at the time
subplot_tight(2,2,1)
imshow(RGB)
title('Original Image');
subplot_tight(2,2,3)
% idk why the original plotted the input image twice
% i'm just going to plot the binarized image
% since that's why this whole mess wouldn't work in the first place
imshow(Bw)
title('Binarized Image');
subplot_tight(2,2,2)
imshow(Bw)
title('Classified Shapes');
for k = 1:numblobs
ht = text(blobcentroids(k,1),blobcentroids(k,2),shapeclasses{blobclasses(k)});
set(ht,'horizontalalignment','center','fontsize',fontsize,'backgroundcolor',textbgc)
end
subplot_tight(2,2,4)
imshow(Bw)
title('Area in m^2');
for k = 1:numblobs
ht = text(blobcentroids(k,1),blobcentroids(k,2),sprintf('%.3f',blobaream(k)));
set(ht,'horizontalalignment','center','fontsize',fontsize,'backgroundcolor',textbgc)
end
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% create an image with blobs colored by class
% this could also have been done in the main loop
labeledbyclass = zeros(size(Bw),'uint16'); % integer-class
for k = 1:numblobs
thisblobonly = L==k;
labeledbyclass(thisblobonly) = blobclasses(k);
end
% labeloverlay() was not available in 2014
% treat the new label image as an indexed image
% indexed image mapping depends on the numeric class
% for float inputs, mapping starts at 1
% for integer-class inputs, mapping starts at 0
CT = brewermap(numblobs,'paired'); % create the color table
CT = [0 0 0; CT]; % include a black row for the background
coloredbyclass = ind2rgb(labeledbyclass,CT);
figure
imshow(coloredbyclass)
This uses subplot_tight() and brewermap() from the File Exchange. Both would have been available at the time, so I think that's fair. I used brewermap() here simply as a quick way to get a categorical colormap that's long enough for the 10 classes given. The built-in lines() map is not. There would have been alternatives to both.
Note that the classification doesn't actually work very well. I didn't bother to fix that. This was mostly just an exercise creating the colored label image with period-correct tools, but it got sidetracked by simplifying existing code without actually digging into OP's classification approach. Similarly, I'm not touching the question of whether doing edge detection is even an appropriate part of the binarization task. Maybe I'll come back to this some other day.
EDIT: Nevermind; I went ahead and made the classification work at least. It's still not great, but at least it works for this image, and the console dump is helpfully formatted.
You might ask why there aren't any circles or squares detected. That's because there aren't any. Test it with a different image:
0 Comments
See Also
Categories
Find more on Convert Image Type in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!