Extracting edges from a shape

Hello all.
I have an irregular form shape like in the image(s) below (created using inpolygon).
I only want to extract the outer edges of this shape, so that I can only have an idea of what the shape is (rather than the complete internal points).
I used contours (imcontour) module which highlights the regions I desire to attain (as shown in the image below).
So I only want to attain these yellow regions.
Help will be much appreciated. Thanks in advance :)

1 Commento

DGM
DGM il 19 Dic 2022
Modificato: DGM il 19 Dic 2022
If the hatched pattern was created using inpolygon(), doesn't that imply that you already have the polygon that defines the boundary?
It would help to have an example that describes the form of the data and the steps taken to get it into that form.

Accedi per commentare.

 Risposta accettata

Alright, I created the binary image in Photoshop from your red crosshairs screenshot. It's attached. Then I wrote code for it to get the perimeter image, and also a list of (x,y) coordinates in a round-the-clock sorted fashion using bwboundaries
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 = 20;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
folder = [];
baseFileName = 'binaryImage.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);
% 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)
end
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage);
impixelinfo;
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Maximize window.
g = gcf;
g.WindowState = 'maximized';
drawnow;
% Binarize
binaryImage = grayImage > 128;
% Call bwperim
perimImage = bwperim(binaryImage);
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 2);
imshow(perimImage);
impixelinfo;
axis('on', 'image');
title('Perimeter Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Find xp and yp (unsorted)
[yp, xp] = find(perimImage);
% Find boundaries (which will be sorted)
% Plot the borders of all the blobs in the overlay above the original grayscale image
% using the coordinates returned by bwboundaries().
% bwboundaries() returns a cell array, where each cell contains the row/column coordinates for an object in the image.
subplot(2, 2, 3);
imshow(grayImage); % Optional : show the original image again. Or you can leave the binary image showing if you want.
% Here is where we actually get the boundaries for each blob.
boundaries = bwboundaries(binaryImage);
% boundaries is a cell array - one cell for each blob.
% In each cell is an N-by-2 list of coordinates in a (row, column) format. Note: NOT (x,y).
% Column 1 is rows, or y. Column 2 is columns, or x.
numberOfBoundaries = size(boundaries, 1); % Count the boundaries so we can use it in our for loop
% Here is where we actually plot the boundaries of each blob in the overlay.
hold on; % Don't let boundaries blow away the displayed image.
for k = 1 : numberOfBoundaries
thisBoundary = boundaries{k}; % Get boundary for this specific blob.
x = thisBoundary(:,2); % Column 2 is the columns, which is x.
y = thisBoundary(:,1); % Column 1 is the rows, which is y.
plot(x, y, 'r-', 'LineWidth', 3); % Plot boundary in red.
end
hold off;
caption = sprintf('%d Outlines, from bwboundaries()', numberOfBoundaries);
fontSize = 15;
title(caption, 'FontSize', fontSize);
axis('on', 'image'); % Make sure image is not artificially stretched because of screen's aspect ratio.

6 Commenti

Yes thanks so much for the answer, it worked to a large degree.
One final thing though, you said you created a binary image using photoshop of the image I provided.
Is it always essential to edit the image using photoshop?
For instance, when I provided the binary image, the code draws perimeter boundary and outline perfectly fine.
However, when I provided the image (attached below), converted to grayscale, the output wasn't what I was looking for.
Input
Output:
The Original Gray Scale Image is one you provided. It was only included in the final image, it isn't being used to produce the perimeter image and outlines in this case.
Can you help me convert the input image to proper gray scale image so that it will always provide the exterior boundary as perimeter image or outline (and I would prefer something other than Photoshop)?
Thanks for all the help again :)
It looks like youi don't have an image. It seems that you have created a graph (which you called an image) by plotting a bunch of markers (+ or o) onto an axes (graph).
How did you get those (x,y) points in the first place? Did you get them by passing a binary image into find()? If so you should start with that binary image.
It is possible to create a binary image from a list of INTEGER (x,y) coordinates. If you have the coordinates, attach them in a .mat file.
I have latitudes and longitudes where there is a coverage for an area. For latitudes, Top Left point is 26.4440438649287 and Bottom Right is 25.1675500815495. For longitudes, TL is 63.4086741290151 and BR is 64.81901969688983.
I am attaching the desired latitudes and desired longitudes txt files. These are those points where you can say the mobile is "visible" or receives proper signals from the antenna.
After it, I use inpolygon function which gives me x and y points. I am attaching the code.
The contour module gives the output which I am attaching.
After this I execute the code you provided yesterday.
My problem is that the image generated using inpolygon (in, on) gives the output which is shown in Edge Shape 1 image.
When I use this to convert to Gray Scale and then I run the code, the desired output is not obtained.
I need to convert Edge Shape 1 image to something like the image you provided me (Binary Image). And I would prefer it without Photoshop.
[in, on ] = inpolygon(desiredlats, desiredlongs, tgtlats, tgtlongs);
figure
%plot(tgtlongs,tgtlats) % polygon
axis equal
hold on
plot(desiredlongs(in),desiredlats(in),'r.') % points inside
%plot(desiredlongs(on),desiredlats(on),'ro') % points on
plot(desiredlongs(~in),desiredlats(~in),'g') % points outside
hold off
image = imread('Edge Shape 1.png');
imggray = rgb2gray(image);
imshow(imggray)
figure;
[contours, h] = imcontour(imggray, 2); % drawing contours
[rows, columns, numberOfColorChannels] = size(imggray);
Did you try the boundary function? I think it could do it.
I tried it before but did not give adequate result. Anyways I'll try it again.
Thanks so much Image Analyst.
Boundary function works fine.
Thanks all along :)

Accedi per commentare.

Più risposte (1)

If you have a digital image, you can use bwperim or bwboundaries
Snippet for you to modify:
% Plot the borders of all the blobs in the overlay above the original grayscale image
% using the coordinates returned by bwboundaries().
% bwboundaries() returns a cell array, where each cell contains the row/column coordinates for an object in the image.
imshow(originalImage); % Optional : show the original image again. Or you can leave the binary image showing if you want.
% Here is where we actually get the boundaries for each blob.
boundaries = bwboundaries(mask);
% boundaries is a cell array - one cell for each blob.
% In each cell is an N-by-2 list of coordinates in a (row, column) format. Note: NOT (x,y).
% Column 1 is rows, or y. Column 2 is columns, or x.
numberOfBoundaries = size(boundaries, 1); % Count the boundaries so we can use it in our for loop
% Here is where we actually plot the boundaries of each blob in the overlay.
hold on; % Don't let boundaries blow away the displayed image.
for k = 1 : numberOfBoundaries
thisBoundary = boundaries{k}; % Get boundary for this specific blob.
x = thisBoundary(:,2); % Column 2 is the columns, which is x.
y = thisBoundary(:,1); % Column 1 is the rows, which is y.
plot(x, y, 'r-', 'LineWidth', 2); % Plot boundary in red.
end
hold off;
caption = sprintf('%d Outlines, from bwboundaries()', numberOfBoundaries);
fontSize = 15;
title(caption, 'FontSize', fontSize);
axis('on', 'image'); % Make sure image is not artificially stretched because of screen's aspect ratio.

6 Commenti

What's mask in this code? Just the image in gray scale?
mask is the digital image you create. What did you start with? An image, or an N-by-2 list of (x,y) coordinates? If the latter, where did they come from? Even if you have such a list you can create a binary image and set those points to true, thus creating a mask image.
mask = false(rows, columns);
for k = 1 : length(x)
mask(y(k), x(k)) = true;
end
Actually, I have an image (Image 1) in the above post, saved in .png form.
I also have an image (contour) saved in .png format.
I converted both to gray scale and binary format and used that as mask. Will that work? (It appeared to be not working fine).
Then attach the image, not a screenshot, not a graph with a bunch of red crosshair markers on it, and not a whole figure with tick marks and tick labels, etc. Attach just the bare image alone. Or else attach the (x,y) data you used to create the image and the code to do it.
What I inserted as an image is exactly in png format and I used that to create a grayscale image and then converted to binary (which I used as mask).
Then ran the code you provided.
After that, I attained an image. But the outer edges were highlighted (like the contour image) and I still got the inner regions, which is what I want to remove.
And you forgot to attach that code or image. Alright, I guess I'll have to create an image from the screenshots you supplied and then continue on with a demo after that. I'll need several minutes to do that.

Accedi per commentare.

Community Treasure Hunt

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

Start Hunting!

Translated by