How can one distinguish the background from the foreground and detect the edges of the seedling?
1 次查看(过去 30 天)
显示 更早的评论
What are some effective approaches or methodologies that can be utilized to differentiate between the background and foreground and accurately delineate the edges of the seedling? I am attaching a image with thier expected results.
input and expect output is
回答(1 个)
Image Analyst
2023-6-15
This is pretty trivial. Simply use the Color Thresholder on the Apps tab of the tool ribbon. Use it and export the function. Write back if you can't figure it out.
11 个评论
Dynamic
2023-6-15
@Image Analyst Sorry for minimul information I have provided. I want an automated code
Image Analyst
2023-6-15
编辑:Image Analyst
2023-6-15
Did you even attempt to use the Color Threshold to generate "auomated" code? And what do you really want? Just the edges (then what)? The area? The color? The area fraction? I mean, you must want something other than the edges, which don't do you much good as a final result.
To learn other fundamental concepts, invest 2 hours of your time here:
Image Analyst
2023-6-16
OK, I guess you're having a lot of trouble. Try this:
% Demo to find area and boundaries of a green region.
% By Image Analyst.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clearvars;
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 18;
fprintf('Beginning to run %s.m ...\n', mfilename);
%-----------------------------------------------------------------------------------------------------------------------------------
% Read in image.
folder = pwd;
baseFileName = 'dynamic.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
rgbImage = imread(fullFileName);
[rows, columns, numberOfColorChannels] = size(rgbImage);
% Display the RGB image full size.
subplot(2, 2, 1);
imshow(rgbImage, []);
axis('on', 'image');
caption = sprintf('Original Image : "%s"', baseFileName);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
% Set up figure properties:
% Enlarge figure to full screen.
hFig1 = gcf;
hFig1.Units = 'Normalized';
hFig1.WindowState = 'maximized';
% Get rid of tool bar and pulldown menus that are along top of figure.
% set(gcf, 'Toolbar', 'none', 'Menu', 'none');
% Give a name to the title bar.
hFig1.Name = 'Demo by Image Analyst';
% Threshold the image to find the leaf.
[mask,maskedRGBImage] = createMask(rgbImage)
% Take the biggest blob
% mask = bwareafilt(mask);
% Display the binary image.
subplot(2, 2, 2);
imshow(mask, []);
axis('on', 'image');
caption = sprintf(' Mask Image');
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
% Get the area 2 different ways.
area1 = bwarea(mask) % Weights according to the shape of the local outline.
area2 = sum(mask(:)) % This is a simple pixel count.
% Get the area (pixel count) and Feret diameters.
props = regionprops(mask, 'Area')
allAreas = [props.Area]
caption = sprintf('Mask Image. %d blobs. Total Area = %d pixels.', numel(allAreas), sum(allAreas));
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.
subplot(2, 2, 3);
imshow(rgbImage); % 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.
%===============================================================================================
function [BW,maskedRGBImage] = createMask(RGB)
%createMask Threshold RGB image using auto-generated code from colorThresholder app.
% [BW,MASKEDRGBIMAGE] = createMask(RGB) thresholds image RGB using
% auto-generated code from the colorThresholder app. The colorspace and
% range for each channel of the colorspace were set within the app. The
% segmentation mask is returned in BW, and a composite of the mask and
% original RGB images is returned in maskedRGBImage.
% Auto-generated by colorThresholder app on 15-Jun-2023
%------------------------------------------------------
% Convert RGB image to chosen color space
I = rgb2hsv(RGB);
% Define thresholds for channel 1 based on histogram settings
channel1Min = 0.160;
channel1Max = 0.302;
% Define thresholds for channel 2 based on histogram settings
channel2Min = 0.303;
channel2Max = 1.000;
% Define thresholds for channel 3 based on histogram settings
channel3Min = 0.257;
channel3Max = 0.986;
% Create mask based on chosen histogram thresholds
sliderBW = (I(:,:,1) >= channel1Min ) & (I(:,:,1) <= channel1Max) & ...
(I(:,:,2) >= channel2Min ) & (I(:,:,2) <= channel2Max) & ...
(I(:,:,3) >= channel3Min ) & (I(:,:,3) <= channel3Max);
BW = sliderBW;
% Initialize output masked image based on input image.
maskedRGBImage = RGB;
% Set background pixels where BW is false to zero.
maskedRGBImage(repmat(~BW,[1 1 3])) = 0;
end
Dynamic
2023-6-16
Hi @Image Analyst, thanks for your code. Actually, I am working to solve another complex problem using DL. That is why my system is occupied. I just want the output I have uploaded as expected output. Just edges.
Image Analyst
2023-6-16
Yes, but you haven't said WHY and that is very important. The perimeter image is not the last, final step in your analysis. You're going to do something with that image right? Not just look at it and say, "Cool, that's fun!"
Anyway, you can simply call bwperim on the mask. I added the line of code to do that at the end of the script. Run it when your DL model is done training. (You know you can start two instances of MATLAB at one time, right? So you can work in one instance while the deep learning training is going on in the other instance.)
% Demo to find area and Feret extents of a leaf.
% By Image Analyst.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clearvars;
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 18;
fprintf('Beginning to run %s.m ...\n', mfilename);
%-----------------------------------------------------------------------------------------------------------------------------------
% Read in image.
folder = pwd;
baseFileName = 'dynamic.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
rgbImage = imread(fullFileName);
[rows, columns, numberOfColorChannels] = size(rgbImage);
% Display the RGB image full size.
subplot(2, 2, 1);
imshow(rgbImage, []);
axis('on', 'image');
caption = sprintf('Original Image : "%s"', baseFileName);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
% Set up figure properties:
% Enlarge figure to full screen.
hFig1 = gcf;
hFig1.Units = 'Normalized';
hFig1.WindowState = 'maximized';
% Get rid of tool bar and pulldown menus that are along top of figure.
% set(gcf, 'Toolbar', 'none', 'Menu', 'none');
% Give a name to the title bar.
hFig1.Name = 'Demo by Image Analyst';
hFig1.NumberTitle = "off"
% Threshold the image to find the leaf.
[mask,maskedRGBImage] = createMask(rgbImage)
% Take the biggest blob
% mask = bwareafilt(mask);
% Display the binary image.
subplot(2, 2, 2);
imshow(mask, []);
axis('on', 'image');
caption = sprintf('Mask Image');
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
% Get the area 2 different ways.
area1 = bwarea(mask) % Weights according to the shape of the local outline.
area2 = sum(mask(:)) % This is a simple pixel count.
% Get the area (pixel count) and Feret diameters.
props = regionprops(mask, 'Area')
allAreas = [props.Area]
caption = sprintf('Mask Image. %d blobs. Total Area = %d pixels.', numel(allAreas), sum(allAreas));
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.
subplot(2, 2, 3);
imshow(rgbImage); % 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.
% Get the perimeter as an image instead of in (x,y) coordinates as above.
perimImage = bwperim(mask);
subplot(2, 2, 4);
imshow(perimImage, []);
axis('on', 'image');
caption = sprintf('Perimeter Image');
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
%===============================================================================================
function [BW,maskedRGBImage] = createMask(RGB)
%createMask Threshold RGB image using auto-generated code from colorThresholder app.
% [BW,MASKEDRGBIMAGE] = createMask(RGB) thresholds image RGB using
% auto-generated code from the colorThresholder app. The colorspace and
% range for each channel of the colorspace were set within the app. The
% segmentation mask is returned in BW, and a composite of the mask and
% original RGB images is returned in maskedRGBImage.
% Auto-generated by colorThresholder app on 15-Jun-2023
%------------------------------------------------------
% Convert RGB image to chosen color space
I = rgb2hsv(RGB);
% Define thresholds for channel 1 based on histogram settings
channel1Min = 0.160;
channel1Max = 0.302;
% Define thresholds for channel 2 based on histogram settings
channel2Min = 0.303;
channel2Max = 1.000;
% Define thresholds for channel 3 based on histogram settings
channel3Min = 0.257;
channel3Max = 0.986;
% Create mask based on chosen histogram thresholds
sliderBW = (I(:,:,1) >= channel1Min ) & (I(:,:,1) <= channel1Max) & ...
(I(:,:,2) >= channel2Min ) & (I(:,:,2) <= channel2Max) & ...
(I(:,:,3) >= channel3Min ) & (I(:,:,3) <= channel3Max);
BW = sliderBW;
% Initialize output masked image based on input image.
maskedRGBImage = RGB;
% Set background pixels where BW is false to zero.
maskedRGBImage(repmat(~BW,[1 1 3])) = 0;
end
Dynamic
2023-6-16
Hello @Image Analyst, Thanks for your support. Your generated result and using canny edge detection provide similar results but did you see if some portion of two leaves are overlapping then it will provide one edge shape? That I am not expecting. I just want the image I have shared as the expected output.
Image Analyst
2023-6-16
It depends on how you define green. Did you play around with the sliders in the Color Thresholder? You might also separate blobs with watershed.
Again, WHY is it necessary to have the perimeters and have separations? I'll probably quit helping unless you help me help you by answering my questions. (I don't like having my questions ignored especially when it's to help you.) And don't just say (like so many people do) "I need it because I need it" or something to that effect.
Dynamic
2023-6-16
Hello @Image Analyst, I appreciate your insightful comments. I apologize for neglecting to mention the purpose behind my previous inquiry. This request stems from an assignment for my coursework, where we are required to implement a preprocessing technique. This technique will be applied to a total of 500 images we have on hand. Additionally, a senior student in our laboratory is currently engaged in developing a deep learning model to accurately identify leaf shapes and count them.
Image Analyst
2023-6-16
Good luck with your assignment. Here is an interface that might help with processing hundreds of images:
To identify the leaf shape you might need to eliminate the stem. You could use imopen() but that will change the shape of the perimeter slightly so you'd have to cleverly craft the algorithm so that only the stem is removed and the leaf edges are not changed.
If this Answer solves your original question, then could you please click the "Accept this answer" link to award the answerer with "reputation points" for their efforts in helping you? They'd appreciate it. Thanks in advance. 🙂 Note: you can only accept one answer (so pick the best one) but you can click the "Vote" icon for as many Answers as you want. Voting for an answer will also award reputation points.
Dynamic
2023-6-17
Hello @Image Analyst, thanks for your suggestion. For you, it may be trivial work. Please if you provide me a fully automated code for the same I will be highly thankful. Thanks advanced
Image Analyst
2023-6-17
@Dynamic I can't and won't. I don't want to be responsible for you getting expelled from the university for cheating and unethically turning in someone else's code as your own. You might want to take that risk but I don't want to enable it. Plus you don't learn anything if I just completely do the assignment for you and give you 100% automated, finished, turnkey code to do it all. If you just want that, then hire a consultant. You won't learn anything but they will give you "fully automated code".
I've given you a substantial amount of code already, plus a GUI for batch processing a bunch of files. I think that should be enough for you to continue on with it. If you want a non-GUI, script for batch processing, see the FAQ: https://matlab.fandom.com/wiki/FAQ#How_can_I_process_a_sequence_of_files?
另请参阅
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!发生错误
由于页面发生更改,无法完成操作。请重新加载页面以查看其更新后的状态。
您也可以从以下列表中选择网站:
如何获得最佳网站性能
选择中国网站(中文或英文)以获得最佳网站性能。其他 MathWorks 国家/地区网站并未针对您所在位置的访问进行优化。
美洲
- América Latina (Español)
- Canada (English)
- United States (English)
欧洲
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom(English)
亚太
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)