How to crop and save objects in an image

9 Ansichten (letzte 30 Tage)
Michael Aboud
Michael Aboud am 11 Dez. 2021
Kommentiert: Michael Aboud am 11 Dez. 2021
Hi all
Assuming that I have the following image
What is the best automated method to crop each one of the objects and save it to an indivisual JPG file (for instance), without incorporating any of the surrounding objects in the saved files
Thanks in advance
Michael

Akzeptierte Antwort

Image Analyst
Image Analyst am 11 Dez. 2021
Try this:
% Demo 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 = 16;
fprintf('Beginning to run %s.m ...\n', mfilename);
%-----------------------------------------------------------------------------------------------------------------------------------
% Read in image.
folder = [];
baseFileName = 'assorted objects.jpeg';
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 image.
subplot(2, 2, 1);
imshow(rgbImage, []);
axis('on', 'image');
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
caption = sprintf('Original RGB Image : "%s"\n%d rows by %d columns', baseFileName, rows, columns);
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';
%-----------------------------------------------------------------------------------------------------------------------------------
[mask, maskedRGBImage] = createMask(rgbImage);
% Fill holes
mask = imfill(mask, 'holes');
% Find area of things
subplot(2, 2, 2);
props = regionprops(mask, 'Area')
allAreas = sort([props.Area], 'Descend')
histogram([props.Area], 100)
% Get rid of small things. Looks like things we're interested in are bigger than about 20.
mask = bwareaopen(mask, 20);
% Display the image.
subplot(2, 2, 2);
imshow(mask, []);
axis('on', 'image');
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
title('Initial Mask Image', 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
% Find the properties of all the blobs.
props = regionprops(mask, 'BoundingBox', 'Centroid', 'Image')
numRegions = length(props)
subplot(2, 2, 3);
imshow(mask, []);
axis('on', 'image');
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
title('Final Mask', 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
% 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, 4);
imshow(rgbImage, []);
axis('on', 'image');
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
title('Objects Outlined', 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
% 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, 'b-', 'LineWidth', 2); % Plot boundary in red.
end
hold off;
caption = sprintf('%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.
plotRows = ceil(sqrt(numRegions));
figure;
for k = 1 : numRegions
thisImage = imcrop(rgbImage, props(k).BoundingBox);
% Get the mask for this cropped image.
thisMask = props(k).Image;
% For some reason, thisMask is one pixel narrower and taller than thisImage. Expand it.
thisMask(end+1, end+1) = false;
% Mask out background and other objects.
thisImage = bsxfun(@times, thisImage, cast(thisMask, 'like', rgbImage)); % R2019b and earlier
% Display this cropped, masked image.
subplot(plotRows, plotRows, k);
imshow(thisImage)
end
msgbox('Done!');
%========================================================================================================
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 11-Dec-2021
%------------------------------------------------------
% Convert RGB image to chosen color space
I = rgb2hsv(RGB);
% Define thresholds for channel 1 based on histogram settings
channel1Min = 0.000;
channel1Max = 1.000;
% Define thresholds for channel 2 based on histogram settings
channel2Min = 0.097;
channel2Max = 1.000;
% Define thresholds for channel 3 based on histogram settings
channel3Min = 0.000;
channel3Max = 1.000;
% 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
  3 Kommentare
Image Analyst
Image Analyst am 11 Dez. 2021
Try this:
figure;
outputFolder = fullfile(pwd, 'Individual Images'); % Whatever you want.
if ~isfolder(outputFolder)
mkdir(outputFolder);
end
for k = 1 : numRegions
thisImage = imcrop(rgbImage, props(k).BoundingBox);
% Get the mask for this cropped image.
thisMask = props(k).Image;
% For some reason, thisMask is one pixel narrower and taller than thisImage. Expand it.
thisMask(end+1, end+1) = false;
% Mask out background and other objects.
thisImage = bsxfun(@times, thisImage, cast(thisMask, 'like', rgbImage)); % R2019b and earlier
% Display this cropped, masked image.
subplot(plotRows, plotRows, k);
imshow(thisImage)
baseFileName = sprintf('Image #%2.2d.png', k);
fullFileName = fullfile(outputFolder, baseFileName);
imwrite(thisImage, fullFileName);
end
Michael Aboud
Michael Aboud am 11 Dez. 2021
It works amazing! Thank you so much for your assistance!

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (1)

Image Analyst
Image Analyst am 11 Dez. 2021
Bearbeitet: Image Analyst am 11 Dez. 2021
This is covered in my Image Segmentation Tutorial:
Sounds a lot like homework so I'll just give hints so you don't get into trouble with your professor. This is the approach I'd try
  1. Use the Color Thresholder app on the Apps tab to get a mask of the background. Use HSV color space and threshold the saturation to be around 0-0.25.
  2. Invert the background mask to get a mask of the object blobs.
  3. Call imfill() to fill any holes in them.
  4. Call bwareaopen() to get rid of any really small noise blobs.
  5. Call regionprops() and ask for BoundingBox and Image.
  6. Loop over all items calling imcrop() with the bounding box and multiplying by the Image. This will crop the object and blacken anything else, like background or other objects protruding into the box.
  7. Then call imwrite().
If you have any trouble, ask, but if it's your homework you might want to consider whether you should be posting your code or not.
  1 Kommentar
Michael Aboud
Michael Aboud am 11 Dez. 2021
Thanks for your reply,
Actually it's not a homework, but I'm coming from a different background with shallow coding experience and I have similar tasks to do with some of my samples. I'm somewhat aquainted with your tutorial (many thanks for that also!), but I couldn't figure out how to crop the blobs only without surroundings and how to save the images in seperate files after cropping
Can you please assist me on how to adjust your code so these requirments can be excuted
Thank you

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Matrix Indexing finden Sie in Help Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by