Split a rhombus in an image into four through centroid

I need to find the area of 4 partitions of the rhombus like image. Thank you in advance for the support.
The partition should be based on the centre point and the corners of rhombus. Assuming rombus may be angled.

 Réponse acceptée

Try this:
% Demo by Image Analyst
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 22;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
folder = [];
baseFileName = 'rhombus.png';
fullFileName = fullfile(folder, baseFileName);
% Check if file exists.
if ~exist(fullFileName, 'file')
% The file doesn't exist -- didn't find it there in that folder.
% Check the entire search path (other folders) for the file by stripping off the folder.
fullFileNameOnSearchPath = baseFileName; % No path this time.
if ~exist(fullFileNameOnSearchPath, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist in the search path folders.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
grayImage = imread(fullFileName);
% Get the dimensions of the image.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(grayImage)
if numberOfColorChannels > 1
% It's not really gray scale like we expected - it's color.
fprintf('It is not really gray scale like we expected - it is color\n');
% Extract the blue channel.
grayImage = rgb2gray(grayImage);
end
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage);
impixelinfo;
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Update the dimensions of the image.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(grayImage)
% Maximize window.
g = gcf;
g.WindowState = 'maximized';
drawnow;
%--------------------------------------------------------------------------------------------------------
% Show the histogram
subplot(2, 2, 2);
imhist(grayImage);
title('Histogram of Original Image', 'FontSize', fontSize, 'Interpreter', 'None');
grid on;
%--------------------------------------------------------------------------------------------------------
% Interactively and visually set a threshold on a gray scale image.
% https://www.mathworks.com/matlabcentral/fileexchange/29372-thresholding-an-image?s_tid=srchtitle
lowThreshold = 58;
highThreshold = 255;
% [lowThreshold, highThreshold] = threshold(lowThreshold, highThreshold, grayImage)
%--------------------------------------------------------------------------------------------------------
% Create a mask
mask = grayImage >= lowThreshold & grayImage <= highThreshold;
% Fill blobs
mask = imfill(mask,"holes");
% Take largest blob only.
mask = bwareafilt(mask, 1);
subplot(2, 2, 3);
imshow(mask, []);
impixelinfo;
axis('on', 'image');
title('Mask', 'FontSize', fontSize, 'Interpreter', 'None');
%--------------------------------------------------------------------------------------------------------
% Measure blob features.
labeledImage = bwlabel(mask);
props = regionprops(mask, grayImage, 'WeightedCentroid', 'Centroid');
if isempty(props)
msgbox('No blobs found.')
return;
end
fprintf('Found %d blobs.\n', numel(props))
% Get the weighted centroid. Not sure which centroid you want.
% xCentroid = props.WeightedCentroid(1);
% yCentroid = props.WeightedCentroid(2);
% Get the unweighted centroid.
xCentroid = props.Centroid(1);
yCentroid = props.Centroid(2);
% Draw lines for the quadrants.
hold on;
xline(xCentroid, 'LineWidth', 2, 'Color', 'r');
yline(yCentroid, 'LineWidth', 2, 'Color', 'r');
hold off;
subplot(2, 2, 1);
hold on;
xline(xCentroid, 'LineWidth', 2, 'Color', 'r');
yline(yCentroid, 'LineWidth', 2, 'Color', 'r');
hold off;
% Get the area of the 4 quadrants. Dividing lines align with the edges of the image.
% Get area of upper left.
quad1 = mask(1 : floor(yCentroid), 1 : floor(xCentroid));
areaUpperLeft = nnz(quad1)
% Get area of upper right.
quad2 = mask(1 : floor(yCentroid), ceil(xCentroid) : end);
areaUpperRight = nnz(quad1)
% Get area of lower left.
quad3 = mask(ceil(yCentroid) : end, 1 : floor(xCentroid));
areaLowerLeft = nnz(quad1)
% Get area of lower right.
quad4 = mask(ceil(yCentroid) : end, ceil(xCentroid) : end);
areaLowerRight = nnz(quad1)
% Show areas as bar chart.
areas = [areaUpperLeft, areaUpperRight, areaLowerLeft, areaLowerRight];
subplot(2, 2, 4);
bar(areas);
title('Areas of Quadrants', 'FontSize', fontSize)
xlabel('Quadrant', 'FontSize', fontSize)
ylabel('Area in pixels', 'FontSize', fontSize)
grid on;

7 commentaires

I am sorry.. But I need to partition only the blob into 4 through centroid of the blob and find area of each blob partition.
Why are you sorry? I did it for you. What's the problem?
D D
D D le 14 Déc 2022
Modifié(e) : D D le 14 Déc 2022
I got your idea! Thank You.. 2 doubts.
1) When I add up 4 area together, it is not exactly same as total blob area. (I made some changes in code, since I am working in Simulink)
buff = imread('11101kaz-MO_100-DPY2_2mA.png');
Map = rgb2gray(buff);
mask = imbinarize(Map);
mask = imfill(mask,"holes");
% Take largest blob only.
mask = bwareafilt(mask, 1);
[X Y] = size(mask);
quad1 = mask(1 : floor(Cent_Y), 1 : floor(Cent_X));
area1 = nnz(quad1);
% Get area of upper right.
quad2 = mask(1 : floor(Cent_X), ceil(Cent_X) : Y);
area2 = nnz(quad2);
% % Get area of lower left.
quad3 = mask(ceil(Cent_X) : X, 1 : floor(Cent_X));
area3 = nnz(quad3);
% % Get area of lower right.
quad4 = mask(ceil(Cent_X) : X, ceil(Cent_X) : Y);
area4 = nnz(quad4);
2) Won't the partition be wrong, if the rhombus is slightly angled.
Is there a way to find the cordinate whether the bounding box meets the corners, rather than assuming the axes as horizontal and perpendicular.
Corners of each quandrant will be centre point and corners of rhombus.
PS: I am a beginner in MATLAB and Image Processing.
Sorry, I made a copy and paste error - forgot to change quadrants in the nnz() calls. Corrected code is below. The area of the whole mask now sums to the area of the quadrants. But I see you discovered that bug and fixed it so your quadrant areas should all sum to the area of the mask. What do you get when you do
theSum = area1 + area2 + area3 + area4
theSum2 = nnz(mask)
Here is my corrected demo:
% Demo by Image Analyst
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 22;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
folder = [];
baseFileName = 'rhombus.png';
fullFileName = fullfile(folder, baseFileName);
% Check if file exists.
if ~exist(fullFileName, 'file')
% The file doesn't exist -- didn't find it there in that folder.
% Check the entire search path (other folders) for the file by stripping off the folder.
fullFileNameOnSearchPath = baseFileName; % No path this time.
if ~exist(fullFileNameOnSearchPath, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist in the search path folders.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
grayImage = imread(fullFileName);
% Get the dimensions of the image.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(grayImage)
if numberOfColorChannels > 1
% It's not really gray scale like we expected - it's color.
fprintf('It is not really gray scale like we expected - it is color\n');
% Extract the blue channel.
grayImage = rgb2gray(grayImage);
end
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage);
impixelinfo;
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Update the dimensions of the image.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(grayImage)
% Maximize window.
g = gcf;
g.WindowState = 'maximized';
drawnow;
%--------------------------------------------------------------------------------------------------------
% Show the histogram
subplot(2, 2, 2);
imhist(grayImage);
title('Histogram of Original Image', 'FontSize', fontSize, 'Interpreter', 'None');
grid on;
%--------------------------------------------------------------------------------------------------------
% Interactively and visually set a threshold on a gray scale image.
% https://www.mathworks.com/matlabcentral/fileexchange/29372-thresholding-an-image?s_tid=srchtitle
lowThreshold = 58;
highThreshold = 255;
% [lowThreshold, highThreshold] = threshold(lowThreshold, highThreshold, grayImage)
%--------------------------------------------------------------------------------------------------------
% Create a mask
mask = grayImage >= lowThreshold & grayImage <= highThreshold;
% Fill blobs
mask = imfill(mask,"holes");
% Take largest blob only.
mask = bwareafilt(mask, 1);
subplot(2, 2, 3);
imshow(mask, []);
impixelinfo;
axis('on', 'image');
title('Mask', 'FontSize', fontSize, 'Interpreter', 'None');
%--------------------------------------------------------------------------------------------------------
% Measure blob features.
labeledImage = bwlabel(mask);
props = regionprops(mask, grayImage, 'WeightedCentroid', 'Centroid');
if isempty(props)
msgbox('No blobs found.')
return;
end
fprintf('Found %d blobs.\n', numel(props))
% Get the weighted centroid. Not sure which centroid you want.
% xCentroid = props.WeightedCentroid(1);
% yCentroid = props.WeightedCentroid(2);
% Get the unweighted centroid.
xCentroid = props.Centroid(1);
yCentroid = props.Centroid(2);
% Draw lines for the quadrants.
hold on;
xline(xCentroid, 'LineWidth', 2, 'Color', 'r');
yline(yCentroid, 'LineWidth', 2, 'Color', 'r');
hold off;
subplot(2, 2, 1);
hold on;
xline(xCentroid, 'LineWidth', 2, 'Color', 'r');
yline(yCentroid, 'LineWidth', 2, 'Color', 'r');
hold off;
% Get the area of the 4 quadrants. Dividing lines align with the edges of the image.
% Get area of upper left.
quad1 = mask(1 : floor(yCentroid), 1 : floor(xCentroid));
areaUpperLeft = nnz(quad1)
% Get area of upper right.
quad2 = mask(1 : floor(yCentroid), ceil(xCentroid) : end);
areaUpperRight = nnz(quad2)
% Get area of lower left.
quad3 = mask(ceil(yCentroid) : end, 1 : floor(xCentroid));
areaLowerLeft = nnz(quad3)
% Get area of lower right.
quad4 = mask(ceil(yCentroid) : end, ceil(xCentroid) : end);
areaLowerRight = nnz(quad4)
% Show areas as bar chart.
areas = [areaUpperLeft, areaUpperRight, areaLowerLeft, areaLowerRight];
subplot(2, 2, 4);
bar(areas);
title('Areas of Quadrants', 'FontSize', fontSize)
xlabel('Quadrant', 'FontSize', fontSize)
ylabel('Area in pixels', 'FontSize', fontSize)
grid on;
theSum = areaUpperRight + areaUpperLeft + areaLowerRight + areaLowerLeft
nnz(mask)
As far as a tilted rhombus, it's not in general a perfect rhombus. It could be an arbitrary quadrilateral. For example if you located the vertices of the shape (see attached demo) the lines drawn between vertices could not in general intersect at exactly 90 degrees. So now the lines separating the quadrants of the shape could be drawn such that they cut across pixels, giving areas of a partial pixel. How do you want to handle that? Do you NEED to handle that? There is a variety of ways to handle that but they're all somewhat complicated. For example you could find the centroid, find the distance of the boundary to the centroid, call findpeaks to find the vertices, take the farthest vertices and one directly across from it and determine the angle, rotate the image so that it is aligned with the vertical and horizontal axes, then compute the quadrant areas as I have already done. But is all that really necessary? What are you going to do with the information once you have it? We need to know that to determine if it's really needed.
Thank you for your reply.
Lets me explain my final requirements
1) Find area of partitions ①,②,③ and ④
2) Find lengths of 4 dotted lines l1,l2,l3 and l4 ( From Centre)
3) Find angles of 4 dotted lines l1,l2,l3 and l4 from the center to the vertices of each entity
For finding above data, first I wanted to figureout the cordinates at the corners. I attempted different methods. And finally the below logic giving an approximate result. Here I searches through the bounding box (logic may not be excellent)
buff = imread('11101kaz-MO_100-DPY2_2mA.png');
Map = rgb2gray(buff);
mask = imbinarize(Map);
mask = imfill(mask,"holes");
%iterate through ounding box)
Cellcol = bb(1);
Cellrow= bb(2);
Firsthigh = int32(0);
Lasthigh = int32(0);
Cellvalue = logical(0);
% Find upper point
for i = 0:bb(3)
Cellvalue = mask(Cellrow, Cellcol+i);
if(1 == Cellvalue)
Firsthigh = i;
break;
end
end
for i= bb(3):-1:0
Cellvalue = mask(Cellrow, Cellcol+i);
if(1 == Cellvalue)
Lasthigh = i;
break;
end
end
UpperMiddlepoint = bb(1)+ Firsthigh + ceil(0.5*(Lasthigh-Firsthigh));
% Find lower point
Firsthigh = int32(0);
for i = 0:bb(3)
Cellvalue = mask(Cellrow+bb(4)-1, Cellcol+i);
if(1 == Cellvalue)
Firsthigh = i;
break;
end
end
Lasthigh = int32(0);
for i= bb(3):-1:0
Cellvalue = mask(Cellrow+bb(4)-1, Cellcol+i);
if(1 == Cellvalue)
Lasthigh = i;
break;
end
end
LowerMiddlepoint = bb(1)+ Firsthigh + ceil(0.5*(Lasthigh-Firsthigh));
% Find left point
Firsthigh = int32(0);
for i = 0:bb(4)
Cellvalue = mask(Cellrow+i, Cellcol);
if(1 == Cellvalue)
Firsthigh = i;
break;
end
end
Lasthigh = int32(0);
for i= bb(4):-1:0
Cellvalue = mask(Cellrow+i, Cellcol);
if(1 == Cellvalue)
Lasthigh = i;
break;
end
end
LeftMiddlepoint = bb(2) + Firsthigh + ceil(0.5*(Lasthigh-Firsthigh));
% Find right point
Firsthigh = int32(0);
for i = 0:bb(4)
Cellvalue = mask(Cellrow+i, Cellcol+bb(3)-1); % Check why -1 was needed
if(1 == Cellvalue)
Firsthigh = i;
break;
end
end
Lasthigh = int32(0);
for i= bb(4):-1:0
Cellvalue = mask(Cellrow+i, Cellcol+bb(3)-1);
if(1 == Cellvalue)
Lasthigh = i;
break;
end
end
RightMiddlepoint = bb(2) + Firsthigh + ceil(0.5*(Lasthigh-Firsthigh));
imshow(mask);
hold on
%plot(x,y,'b','LineWidth',2)
plot(bb(1)+bb(3),RightMiddlepoint, 'r+', 'MarkerSize', 30, 'LineWidth', 2);
plot(bb(1),LeftMiddlepoint, 'r+', 'MarkerSize', 30, 'LineWidth', 2);
plot(LowerMiddlepoint,bb(2)+bb(4), 'r+', 'MarkerSize', 30, 'LineWidth', 2);
plot(UpperMiddlepoint,bb(2), 'r+', 'MarkerSize', 30, 'LineWidth', 2);
plot(Cent_X,Cent_Y, 'r+', 'MarkerSize', 30, 'LineWidth', 2);
rectangle('Position',[bb(1) bb(2) bb(3) bb(4)],'EdgeColor','green');
hold off
The result I obtained is below. Now I am need to measure the items in my requirement list.
I already knew that. You basically just repeated saying that you need to measure the quadrants. But you didn't say why even though I asked directly. Maybe it's secret or proprietary and that's why you won't tell anyone.
But how will your algorithm work on the attached image?
Does it find the vertices? (Like the attached demo)
I understood your point.. But Such a big tilt is not expected in the input image.. Thank you for helping me with solving the problem..

Connectez-vous pour commenter.

Plus de réponses (1)

Image Analyst
Image Analyst le 12 Déc 2022
If you still can't figure it out (how to get the centroid and use indexing to split it into 4 parts) then write back, but it should be pretty easy.

Catégories

Community Treasure Hunt

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

Start Hunting!

Translated by