What changes should I make to get binary images correctly in order for BoundingBox to grab the ROI correctly?
1 view (last 30 days)
Show older comments
I am not getting the correct binary images of the attached images in order for the BoundingBox to capture the ROI properly. It happens only for a few images most likely due to the pixel values that are thresholded. What modifications would have to be done in the code to get the correct binary image in order to capture the ROI properly for these images. The original images attached are in RGB color. The corresponding binary image are displayed below.
folder = 'I:\converted images\0.5\0.5 2 mm offset';
baseFileName = '0.5 cmc 2mm off0590.tif';
fullFileName = fullfile(folder, baseFileName);
% Check if file exists.
if ~isfile(fullFileName)
% 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
fullFileName = fullFileNameOnSearchPath;
end
[grayImage,map] = imread(fullFileName);
grayImage = rgb2gray(grayImage);
imshow(grayImage,map)
binaryImage = ~imbinarize(grayImage);
% Erase from line 758 down:
binaryImage(758:end, :) = false;
% Fill holes.
binaryImage = imfill(binaryImage, 'holes');
% Get rid of any msall noise blobs.
binaryImage = bwareafilt(binaryImage, 1); % Take largest blob only.
imshow(binaryImage)
impixelinfo;
props = regionprops(binaryImage, 'BoundingBox');
spreadingWidth = props.BoundingBox(3)
rectangle('Position', props.BoundingBox, 'Edgecolor', 'g', 'LineWidth', 2)
0 Comments
Accepted Answer
Image Analyst
on 12 Jun 2021
This seems to work for all the images you attached.
% 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 = 20;
folder = pwd; 'I:\converted images\0.5\0.5 2 mm offset';
baseFileName = 'image 4.jpg';
fullFileName = fullfile(folder, baseFileName);
% Check if file exists.
if ~isfile(fullFileName)
% 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
fullFileName = fullFileNameOnSearchPath;
end
[grayImage,map] = 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.
% Extract the red channel (so the magenta lines will be white).
grayImage = grayImage(:, :, 1);
end
subplot(2, 3, 1);
imshow(grayImage,map)
axis('on', 'image');
impixelinfo;
title('Original Image', 'FontSize', fontSize);
g = gcf;
g.WindowState = 'maximized';
% Flatten the image
grayImage = adapthisteq(grayImage);
subplot(2, 3, 2);
imshow(grayImage,map)
axis('on', 'image');
impixelinfo;
title('Background Corrected Image', 'FontSize', fontSize);
% Find the top of the bottom dark stripe
leftStrip = grayImage(:, 1:200);
bw = imbinarize(leftStrip);
bw = bwareaopen(bw, 2000);
verticalProfile = mean(bw, 2);
subplot(2, 3, 3);
% imshow(bw);
plot(verticalProfile, 'b-', 'LineWidth', 2);
grid on;
title('Vertical Profile over left-most 200 columns', 'FontSize', fontSize);
xlabel('Row', 'FontSize', fontSize);
ylabel('Gray Level', 'FontSize', fontSize);
% image 1 seems to have a black line at the top, so whiten the first few lines.
meanGL = mean2(grayImage(2 : round(rows/2)))
grayImage(1 : 3, :) = meanGL;
% Now need to recompute vertical profile.
% verticalProfile = mean(grayImage(:, 1:200), 2);
% Erase from line down:
rowToErase = find(verticalProfile > 0.1, 1, 'last')
grayImage(rowToErase:end, :) = meanGL;
subplot(2, 3, 1);
% imshow(grayImage,map)
yline(rowToErase, 'Color', 'y', 'LineWidth', 2);
subplot(2, 3, 2);
yline(rowToErase, 'Color', 'y', 'LineWidth', 2);
% Get histogram between lines 647 and rowToErase
subplot(2, 3, 4);
imhist(grayImage(647:rowToErase, :));
grid on;
title('Histogram of corrected image', 'FontSize', fontSize);
xlabel('Gray Level', 'FontSize', fontSize);
ylabel('PixelCount', 'FontSize', fontSize);
% Binarize the image.
binaryImage = grayImage < 75;
% Fill holes.
binaryImage = imfill(binaryImage, 'holes');
% Get rid of any small noise blobs.
% Don't use bwareafilt() to take largest blob because sometimes the blob is split into two big chunks.
props = regionprops(binaryImage, 'Area');
allAreas = [props.Area]
binaryImage = bwareaopen(binaryImage, 6000); % Take only blobs larger than 5000 pixels.
subplot(2, 3, 5);
imshow(binaryImage)
axis('on', 'image');
impixelinfo;
title('Mask Image', 'FontSize', fontSize);
% Find bounding box.
[r, c] = find(binaryImage);
row1 = min(r)
row2 = max(r)
col1 = min(c)
col2 = max(c)
xline(col1, 'Color', 'r', 'LineWidth', 2);
xline(col2, 'Color', 'r', 'LineWidth', 2);
spreadingWidth = col2 - col1
caption = sprintf('Mask Image. SpreadingWidth = %.1f pixels', spreadingWidth);
title(caption, 'FontSize', fontSize);
% Find the bottom row as the lowest row where the blob hits the side of the bounding box.
% This will let us ignore parts of the blob that are below the outer edges of the blob,
% which seems to be like a reflection of the droplet.
lastRowLeft = find(binaryImage(:, col1), 1, 'last')
lastRowRight = find(binaryImage(:, col2), 1, 'last')
% Draw red lines to edges.
line([1, col1], [lastRowLeft, lastRowLeft], 'Color', 'r', 'LineWidth', 2);
line([col2, columns], [lastRowRight, lastRowRight], 'Color', 'r', 'LineWidth', 2);
% Find the lowest of the two rows.
lastRow = max(lastRowLeft, lastRowRight)
spreadingHeight = lastRow - row1
% Make up a rectangle vector in the form [x, y, width, height]
rectPosition = [col1, row1, spreadingWidth, spreadingHeight]
rectangle('Position', rectPosition, 'Edgecolor', 'g', 'LineWidth', 2)
subplot(2, 3, 2);
rectangle('Position', rectPosition, 'Edgecolor', 'g', 'LineWidth', 2)
g = gcf;
g.WindowState = 'maximized';
10 Comments
Image Analyst
on 15 Jun 2021
It's a 16 bit image in the range 0-65535, not an 8 bit image in the range 0-255, so you need to change the threshold used in getting the binary image from 75 to something that works.
More Answers (1)
Image Analyst
on 12 Jun 2021
Looks like it's working for the images you gave it, however you gave it improperly segmented images. Sometimes you need to adjust the parameters to imbinarize, threshold it manually, or use a more sophisticated algorithm. Or improve your image capture method to get a better image in the first place.
3 Comments
Image Analyst
on 12 Jun 2021
The original ones you posted don't open in Firefox, but these do. I'll try to remember to check them later today. I need to go do something now.
See Also
Categories
Find more on Image Segmentation and Analysis in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!