Image Processing using ginput for Grain Size Analysis
2 vues (au cours des 30 derniers jours)
Afficher commentaires plus anciens
The idea is the use a coin as a measurement reference in order to determine the size of the ash.
So the size of the coin isn't always the smallest or largest part of the image and I'm having trouble specifying this in my code. I know there is a way where I can use the function "ginput" so I can have the user iput/choose the reference point (the coin). Assuming this has to do with my props function (after line 85). This is important to me cause I want to also keep the measurement value (as you'll see in lines 102 and 103) so I can use that to measure other pieces of the image (which I'm still figuring out how to do). Open to suggestions for anyway to measure the ash as well.
Will post the code below and appreciate help as always. Also the image I'm using is above since I felt this was an easier one to use.
close all;
clear all;
%% Read in Image
RGB = imread('20210717_Tamarack_1524.jpg');
% Display Image
figure(1);
clf
imshow(RGB)
%% Convert Truecolor (RGB) Image into Grayscale Image
I = im2gray(RGB);
% Use Median Filter
I = medfilt2(I,[10 10]);
figure(2);
clf
imshow(I)
%% Calculate the Gradient Image and Apply a Threshold
% Use edge and Sobel operator to calculate the threshold value. Then Tune the threshold value and use edge again to obtain a binary mask that contains the segmented cell
[~,threshold] = edge(I,'sobel');
fudgeFactor = 1;
BWs = edge(I,'sobel',threshold * fudgeFactor);
% Display resulting binary gradient mask
figure(3);
clf
imshow(BWs)
%% Dilate the Image.
% Create two perpendicular linear structuring elements by using strel function.
se90 = strel('line',3,90);
se0 = strel('line',3,0);
% Dilate the binary gradient mask using the vertical structuring element followed by the horizontal structuring element. The imdilate function dilates the image.
BWsdil = imdilate(BWs,ones(15,15));
imshow(BWsdil)
% Fill Interior Gaps
% Fill remaining holes using the imfill function
BWdfill = imfill(BWsdil,'holes');
figure(4);
clf
imshow(BWdfill)
%% Remove Connected Objects
% Remove any objects that are connected to the border of the image using
% imclearborder function. We use 4 as connectivity to remove 2D diagonal
% connections
BWnobord = imclearborder(BWdfill,4);
figure(5);
clf
imshow(BWnobord)
%% Smooth the Object
% We create the diamond structuring element using the strel function in
% order to make the object look natual/smooth
seD = strel('diamond',1);
BWfinal = imerode(BWnobord,seD);
BWfinal = imerode(BWfinal,seD);
figure(6);
clf
imshow(BWfinal)
%% Visualize the Segmentation
% Labelloverlay function allows us to display the mask over the original
% image
figure(7);
clf
imshow(labeloverlay(I,BWfinal))
%% bwareafilt function allows us to filter image, retaining (10) or n objects with
% the largest area
bwsizefilt = bwareafilt(BWfinal, 5);
% bwlabel returns the label matrix L that contains labels for the
% objects found in bwsizefilt
L = bwlabel(bwsizefilt);
figure(8);
clf
% Retains plot
hold on
% Creates pseudocolor plot using the values in matrix L
pcolor(L);
set(gca,'ydir','reverse')
% Sets color shading properties
shading flat
% Measure properties of image regions using regionprops
% Calculate centroids and area for connected components in the image.
props = regionprops(bwsizefilt, 'Centroid', 'Area', 'EquivDiameter');
for i = 1:length(props)
plot(props(i).Centroid(1),props(i).Centroid(2), '*k')
end
%% Find out the size of all the blobs so we know what size to use when filtering with bwareaopen.
% props = regionprops(mask, 'Area', 'EquivDiameter', 'Centroid');
allAreas = sort([props.Area]);
% Display the mask image.
% subplot(2, 1, 2);
% Coin radius, can be changed based on reference
% uiwait(msgbox('Choose Reference Point'));
% A = ginput(1);
pennyRadiusInPixels = props(3).EquivDiameter / 2;
pennyRadiusInMm = 19.05 / 2;
% Identify Points
%[x,y] = ginput(1)
%centers = [x,y];
%viscircles(centers,pennyRadiusInMm, 'Color', 'b')
% Overlay the circle over the image.
viscircles([props(3).Centroid(1), props(3).Centroid(2)], pennyRadiusInPixels, 'Color', 'b')
return
% Compute the spatial calibration factor.
mmPerPixel = pennyRadiusInMm / pennyRadiusInPixels
subplot(2, 1, 2);
caption = sprintf('The spatial calibration is %f mm per pixel', mmPerPixel)
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
% 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.
% 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.
subplot(2, 1, 1);
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('Original image with %d Outlines, from bwboundaries()', numberOfBoundaries);
title(caption, 'FontSize', fontSize);
axis('on', 'image'); % Make sure image is not artificially stretched because of screen's aspect ratio.
message = sprintf('Done!\nThe spatial calibration is %f mm per pixel', mmPerPixel)
uiwait(helpdlg(message));
0 commentaires
Réponses (1)
Image Analyst
le 2 Nov 2022
Looks like you made a common beginner mistake: doing an edge detection. Just because you can see edges in an image does not mean edge detection is the right thing to do. Beginners nearly always want to do an edge detection for some reason. Perhaps other inexperienced people told them to do that. It's usually not what is required.
First of all, I'd not use a coin. I'd get bright fluorescent spot stickers at the hobby or office supply store that are a completely different color than the soil. Or you could even use a Post-it note. Then find that color and do your spatial calibration from that.
Then segment your ash in some way that makes sense to differentiate it from the background. I don't know what that might be since I don't know what is ash and what is background in your images.
10 commentaires
Walter Roberson
le 8 Nov 2022
That file has no useful EXIF information. Just the X Resolution and Y Resolution being the nominal "1" which tells you nothing useful.
Voir également
Catégories
En savoir plus sur Image Segmentation and Analysis dans Help Center et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!