How to find the points in the tip of the surface bubble in a given image without manual effort.

1 view (last 30 days)
Hello everyone,
I have an existing script that calculate the angle of the bubble created on the surface. For that i am uploading the image and selecting the rectangle area of the bubble. and then using getpts for selecting 5 points from the tip edge of the bubble is manually selected for furthur calculation.
I want to select those point without manually selecting from the image. Please suggest a solution for this. If i can use any matlab built in function that will get those points.
I am attaching the image and the code.
filename = 'D:\Probe_1030_80ms_02.bmp';
image_raw = imread(filename);
% image_raw = imrotate(image_raw,180);
imshow(image_raw)
% set(gca,'YDir','normal')
rect = getrect
close(figure(1))
% image_raw = imrotate(image_raw,180);
im = image_raw+50;
imshow(image_raw(rect(2):(rect(2)+rect(4)),rect(1):(rect(1)+rect(3))));
%set(gcf,'units','normalized','outerposition',[0 0 1 1]);
[xi,yi] = getpts; % 5 Punkte
close(figure(1))

Accepted Answer

Image Analyst
Image Analyst on 10 Feb 2022
Try this:
% 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 = 22;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
folder = pwd;
baseFileName = 'Probe_1030_80ms_02.bmp';
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);
% 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(rgbImage)
if numberOfColorChannels > 1
% It's not really gray scale like we expected - it's color.
% Extract the blue channel.
grayImage = rgbImage(:, :, 3);
else
grayImage = rgbImage;
end
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 3, 1);
imshow(grayImage);
impixelinfo;
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
hold on
% Maximize window.
g = gcf;
g.WindowState = 'maximized'
drawnow;
%--------------------------------------------------------------------------------------------------------
% Get a histogram
subplot(2, 3, 2);
imhist(grayImage);
grid on;
title('Histogram of Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
%--------------------------------------------------------------------------------------------------------
% Get the vertical profile
% verticalProfile = mean(grayImage, 2);
% subplot(2, 3, 3);
% plot(1:rows, verticalProfile, 'b-');
% grid on;
% xlabel('Row', 'FontSize', fontSize)
% Ylabel('Intensity', 'FontSize', fontSize)
% Assume camera and substrate are fixed and everything below line 426 we can just throw away.
bottomRow = 426;
grayImage(bottomRow:end, :) = 255;
% Take the histogram
counts = histcounts(grayImage(1:bottomRow, :));
%--------------------------------------------------------------------------------------------------------
% Set thresholds for each level.
lowThreshold = 0;
% Get the triangle threshold for the upper threshold
highThreshold = triangle_threshold(counts, 'L', false)
% Interactively and visually set a threshold on a gray scale image.
% https://www.mathworks.com/matlabcentral/fileexchange/29372-thresholding-an-image?s_tid=srchtitle
% [lowThreshold, highThreshold] = threshold(lowThreshold, highThreshold, grayImage)
% Draw threshold line over histogram.
xline(highThreshold, 'Color', 'r', 'LineWidth', 2);
%--------------------------------------------------------------------------------------------------------
% Binarize the image to get a mask.
mask = grayImage >= lowThreshold & grayImage <= highThreshold;
mask = imfill(mask, 'holes');
% Take largest blobs.
mask = bwareafilt(mask, 2);
% Display mask image.
subplot(2, 3, 3);
imshow(mask);
impixelinfo;
axis('on', 'image');
drawnow;
caption = sprintf('Mask with Threshold = %d gray levels', highThreshold);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
% Take the blob closest to the center of the image.
props = regionprops(mask, 'Centroid', 'BoundingBox');
indexOfMin = 1; % Initialize.
if length(props) >= 2
% Extract centroids from structure to arrays.
xy = vertcat(props.Centroid);
x = xy(:, 1);
y = xy(:, 2);
% Find distances from each blob's centroid to the center of the image.
distances = sqrt((x - columns/2) .^ 2 + (y - rows/2) .^ 2);
[minDistance, indexOfMin] = min(distances);
end
% Get the bounding box of the droplet nearest the center.
labeledImage = bwlabel(mask);
mask = ismember(labeledImage, indexOfMin);
bb = props(indexOfMin).BoundingBox;
hold on;
rectangle('Position', bb, 'EdgeColor', 'r');
% Crop the image and display it.
croppedImage = imcrop(grayImage, bb);
mask = imcrop(mask, bb);
[rows, columns] = size(mask);
% Display image.
subplot(2, 3, 4:6);
imshow(croppedImage, []);
impixelinfo;
axis('on', 'image');
drawnow;
caption = sprintf('Mask with Threshold = %d gray levels', highThreshold);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
%--------------------------------------------------------------------------------------------------------
% Scan to get lowest boundary
topRows = nan(1, columns);
x = nan(1, columns);
for col = 1 : columns
t = find(mask(:, col), 1, 'first');
if ~isempty(t)
topRows(col) = t;
x(col) = col;
end
end
% Get rid of nans, which were where there was no white pixels in a column.
x = x(~isnan(x));
topRows = topRows(~isnan(topRows));
% We need to fit the top boundary to a polynomial.
coefficients = polyfit(x, topRows, 2)
yFit = polyval(coefficients, x);
hold on;
plot(x, topRows, 'g-', 'LineWidth', 2);
plot(x, yFit, 'r-', 'LineWidth', 2);
% yFit = coefficients(1) * x ^ 2 + coefficients(2) * x + coefficients(3)
% The derivative is
% Slope = 2 * coefficients(1) * x + coefficients(2);
% Get the slope on the left end where x = 1.
leftSlope = 2 * coefficients(1) * x(1) + coefficients(2)
% Get the slope on the right end where x = the last value.
rightSlope = 2 * coefficients(1) * x(end) + coefficients(2)
% Get the average of the slopes
meanSlope = mean([abs(leftSlope), abs(rightSlope)])
% Get the average angle.
meanAngle = atand(meanSlope)
caption = sprintf('The mean slope is %f and the mean angle is %f degrees', meanSlope, meanAngle);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
% Tell the user
message = sprintf('Done!\nThe mean slope is %f and the mean angle is %f degrees', meanSlope, meanAngle)
uiwait(msgbox(message))
  5 Comments
Chandrashekar D S
Chandrashekar D S on 12 Feb 2022
@Image Analyst Thanks for uploading the file. Can you please look at the other query, i have posting in the comment. The new image is not recognizing because the created bubble is almost in gray colour where the initial bubble image is in balckish gray in colour.
Image Analyst
Image Analyst on 12 Feb 2022
This would require a totally, or mostly, different algorithm. I'm sure you can use the concepts I showed you to make a similar program for this type of image. If this is the main type of image you will have, you should not have asked me to develope an algorithm for that other image.
I suggest you use a fixed camera so that the field of view is constant, and only barely includes the tip where the droplet emerges. Also make the field of view such that it barely fits the largest spread/landed droplet that you ever expect to encounter so that you have as much resolution over the region of interest as possible. It is good though that this second image does not look obliquely onto the surface which caused reflection problems in the first image. It's best to have the optics axis be parallel with the surface the droplet lands on (if the droplets are circularly symmetric after they land and spread).
If you do all these things you can use a fixed threshold, not a variable one, and you can use a fixed mask that excludes stuff you don't want, like the pipette tip and table top. Then you can eliminate some code dealing with finding where the droplet is because you will know where it is.

Sign in to comment.

More Answers (0)

Community Treasure Hunt

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

Start Hunting!