How to analyze area of flow in liquid with a 2D image?
3 Ansichten (letzte 30 Tage)
Ältere Kommentare anzeigen
Christine Nee
am 12 Jan. 2017
Kommentiert: Image Analyst
am 14 Jan. 2017
Hi all. I have written from some tutorials and help pages an image analysis tool which takes a picture and converts it to black and white 8 bit, then thresholds, then selects out groups of flow, then outlines and THEN calculates an area for the ebb that the flow has produced.
I am curious as to how to accurately get my program to outline and group the flow?
Below is the code. You can just replace the image and see what I am talking about. For a more complicated 2D picture representing flow, the outline is inaccurate. Attached is the picture for the code. Thanks
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/159740/image.jpeg)
%This program takes the threshold of the picture and then takes the
%brighter is then converted into area
clc; % Clear command window.
clearvars; % Get rid of variables from prior run of this m-file.
fprintf('Loading Flowdemo.m...\n'); % Message sent to command window.
workspace; % Make sure the workspace panel with all the variables is showing.
imtool close all; % Close all imtool figures.
format long g;
format compact;
captionFontSize = 14;
% Check that user has the Image Processing Toolbox installed.
hasIPT = license('test', 'image_toolbox');
if ~hasIPT
% User does not have the toolbox installed.
message = sprintf('Please install image toolbox');
reply = questdlg(message, 'Toolbox missing', 'Yes', 'No', 'Yes');
if strcmpi(reply, 'No')
% User said No, so exit.
return;
end
end
FileName = 'IMG_4087-793289.JPG';
originalImage = imread(FileName);
% Checks for grayscale images
[rows, columns, numberOfColorChannels] = size(originalImage);
if numberOfColorChannels > 1
promptMessage = sprintf('Your image file has %d color channels.\nThis demo was designed for grayscale images.\nDo you want me to convert it to grayscale for you so you can continue?', numberOfColorChannels);
button = questdlg(promptMessage, 'Continue', 'Convert and Continue', 'Cancel', 'Convert and Continue');
if strcmp(button, 'Cancel')
fprintf(1, 'Finished running micellesDemo.m.\n');
return;
end
% Converts color --> gray
originalImage = rgb2gray(originalImage);
end
% Display the grayscale image of the original image in a full window
subplot(3, 3, 1);
imshow(originalImage);
set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
%Displays a histogram of the colors.
[pixelCount, grayLevels] = imhist(originalImage);
subplot(3, 3, 2);
bar(pixelCount);
title('Histogram of original image', 'FontSize', captionFontSize);
xlim([0 grayLevels(end)]); % Scale x axis manually.
grid on;
%Establishing a Threshold. Black and white
thresholdValue = 100;
binaryImage = originalImage > thresholdValue; % Bright objects will be chosen if you use >.
% Do a "hole fill" to get rid of any background pixels or "holes" inside the micelles.
binaryImage = imfill(binaryImage, 'holes');
% Show the threshold as a vertical red bar on the histogram.
hold on;
maxYValue = ylim;
line([thresholdValue, thresholdValue], maxYValue, 'Color', 'r');
% Place a text label on the bar chart showing the threshold.
annotationText = sprintf('Thresholded at %d gray levels', thresholdValue);
% For text(), the x and y need to be of the data class "double" so let's cast both to double.
text(double(thresholdValue + 5), double(0.5 * maxYValue(2)), annotationText, 'FontSize', 10, 'Color', [0 .5 0]);
text(double(thresholdValue - 70), double(0.94 * maxYValue(2)), 'Background', 'FontSize', 10, 'Color', [0 0 .5]);
text(double(thresholdValue + 50), double(0.94 * maxYValue(2)), 'Foreground', 'FontSize', 10, 'Color', [0 0 .5]);
% Display the binary image.
subplot(3, 3, 3);
imshow(binaryImage);
title('Image converted into Binary after thresholding', 'FontSize', captionFontSize);
% Identifies the conglomerate of micells
labeledImage = bwlabel(binaryImage, 8);
subplot(3, 3, 4);
imshow(labeledImage, []); % Show the gray scale image.
title('Micelle groups', 'FontSize', captionFontSize);
micellMeasurements = regionprops(labeledImage, originalImage, 'all');
numberOfmicell = size(micellMeasurements, 1);
% bwboundaries() returns a cell array, where each cell contains the row/column coordinates for an object in the image.
% Plot the borders of all the micelles on the original grayscale image using the coordinates returned by bwboundaries.
subplot(3, 3, 6);
imshow(originalImage);
title('Outlines, from bwboundaries()', 'FontSize', captionFontSize);
axis image; % Make sure image is not artificially stretched because of screen's aspect ratio.
hold on;
boundaries = bwboundaries(binaryImage);
numberOfBoundaries = size(boundaries, 1);
for k = 1 : numberOfBoundaries
thisBoundary = boundaries{k};
plot(thisBoundary(:,2), thisBoundary(:,1), 'g', 'LineWidth', 2);
end
hold off;
textFontSize = 14; % Used to control size of "micelle number" labels put atop the image.
labelShiftX = -7; % Used to align the labels in the centers of the coins.
micelleECD = zeros(1, numberOfmicell);
% Print header line in the command window.
fprintf(1,'micelle # Mean Intensity Area Perimeter Centroid Diameter\n');
% Loop over all micelles printing their measurements to the command window.
for k = 1 : numberOfmicell % Loop through all micelles.
% Find the mean of each micelle. (R2008a has a better way where you can pass the original image
% directly into regionprops. The way below works for all versions including earlier versions.)
thismicellesPixels = micellMeasurements(k).PixelIdxList; % Get list of pixels in current micelle.
meanGL = mean(originalImage(thismicellesPixels)); % Find mean intensity (in original image!)
meanGL2008a = micellMeasurements(k).MeanIntensity; % Mean again, but only for version >= R2008a
micelleArea = micellMeasurements(k).Area; % Get area.
micellePerimeter = micellMeasurements(k).Perimeter; % Get perimeter.
micelleCentroid = micellMeasurements(k).Centroid; % Get centroid one at a time
micelleECD(k) = sqrt(4 * micelleArea / pi); % Compute ECD - Equivalent Circular Diameter.
fprintf(1,'#%2d %17.1f %11.1f %8.1f %8.1f %8.1f % 8.1f\n', k, meanGL, micelleArea, micellePerimeter, micelleCentroid, micelleECD(k));
% Put the "micelle number" labels on the "boundaries" grayscale image.
text(micelleCentroid(1) + labelShiftX, micelleCentroid(2), num2str(k), 'FontSize', textFontSize, 'FontWeight', 'Bold');
end
2 Kommentare
Image Analyst
am 12 Jan. 2017
Bearbeitet: Image Analyst
am 12 Jan. 2017
We can't read it. Read this: http://www.mathworks.com/matlabcentral/answers/13205#answer_18099 or just attach it with the paper clip icon.
John BG
am 12 Jan. 2017
Bearbeitet: John BG
am 12 Jan. 2017
we can read it but can't guess the image. Please supply the image:
format long g;
format compact; captionFontSize = 14;
FileName = 'IMG_4087-793289.JPG'; originalImage = imread(FileName);
% Checks for grayscale images
[rows, columns, numberOfColorChannels] = size(originalImage);
if numberOfColorChannels > 1 promptMessage = sprintf('Your image file has %d color channels.\nThis demo was designed for grayscale images.\nDo you want me to convert it to grayscale for you so you can continue?', numberOfColorChannels); button = questdlg(promptMessage, 'Continue', 'Convert and Continue', 'Cancel', 'Convert and Continue');
if strcmp(button, 'Cancel') fprintf(1, 'Finished running micellesDemo.m.\n'); return;
end
originalImage = rgb2gray(originalImage);
end
subplot(3, 3, 1);
imshow(originalImage); set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
[pixelCount, grayLevels] = imhist(originalImage);
subplot(3, 3, 2); bar(pixelCount);
title('Histogram of original image', 'FontSize', captionFontSize); xlim([0 grayLevels(end)]);
grid on;
thresholdValue = 100; binaryImage = originalImage > thresholdValue;
binaryImage = imfill(binaryImage, 'holes');
% Show the threshold as a vertical red bar on the histogram. hold on;
maxYValue = ylim; line([thresholdValue, thresholdValue], maxYValue, 'Color', 'r');
annotationText = sprintf('Thresholded at %d gray levels', thresholdValue);
text(double(thresholdValue + 5), double(0.5 * maxYValue(2)), annotationText, 'FontSize', 10, 'Color', [0 .5 0]); text(double(thresholdValue - 70), double(0.94 * maxYValue(2)), 'Background', 'FontSize', 10, 'Color', [0 0 .5]); text(double(thresholdValue + 50), double(0.94 * maxYValue(2)), 'Foreground', 'FontSize', 10, 'Color', [0 0 .5]);
imshow(binaryImage); title('Image converted into Binary after thresholding', 'FontSize', captionFontSize);
labeledImage = bwlabel(binaryImage, 8); subplot(3, 3, 4); imshow(labeledImage, []);
title('Micelle groups', 'FontSize', captionFontSize); micellMeasurements = regionprops(labeledImage, originalImage, 'all'); numberOfmicell = size(micellMeasurements, 1);
subplot(3, 3, 6); imshow(originalImage);
title('Outlines, from bwboundaries()', 'FontSize', captionFontSize); axis image;
hold on; boundaries = bwboundaries(binaryImage); numberOfBoundaries = size(boundaries, 1); for k = 1 : numberOfBoundaries thisBoundary = boundaries{k}; plot(thisBoundary(:,2), thisBoundary(:,1), 'g', 'LineWidth', 2); end hold off;
textFontSize = 14; % Used to control size of "micelle number" labels put atop the image. labelShiftX = -7;
micelleECD = zeros(1, numberOfmicell);
fprintf(1,'micelle # Mean Intensity Area Perimeter Centroid Diameter\n');
for k = 1 : numberOfmicell
thismicellesPixels = micellMeasurements(k).PixelIdxList;
meanGL = mean(originalImage(thismicellesPixels));
meanGL2008a = micellMeasurements(k).MeanIntensity;
micelleArea = micellMeasurements(k).Area;
micellePerimeter = micellMeasurements(k).Perimeter;
micelleCentroid = micellMeasurements(k).Centroid;
micelleECD(k) = sqrt(4 * micelleArea / pi);
fprintf(1,'#%2d %17.1f %11.1f %8.1f %8.1f %8.1f % 8.1f\n', k, meanGL, micelleArea, micellePerimeter, micelleCentroid, micelleECD(k));
text(micelleCentroid(1) + labelShiftX, micelleCentroid(2), num2str(k), 'FontSize', textFontSize, 'FontWeight', 'Bold'); end
Akzeptierte Antwort
John BG
am 12 Jan. 2017
Bearbeitet: John BG
am 12 Jan. 2017
Christine
you only plot 4 images, yet in the command subplot your are telling it to make room for 6 images, let me explain:
1. command subplot(a,b,c) has 3 fields
2. a and b define the a rows b columns that you want the outline to size
so, because you are saying a=3 b=3, command subplot is sizing 9 spaces
3.
field c is the position of the image reading the columns left to right, sequentially.
For 3x3 c would follow this order, start reading top left corner downwards
1 4 7
2 5 8
3 6 9
your code with modified subplot indices, and this image:
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/176553/image.jpeg)
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/176555/image.jpeg)
format long g;
format compact; captionFontSize = 14;
FileName = 'dirty_water.jpg'; originalImage = imread(FileName);
% Checks for grayscale images
[rows, columns, numberOfColorChannels] = size(originalImage);
if numberOfColorChannels > 1 promptMessage = sprintf('Your image file has %d color channels.\nThis demo was designed for grayscale images.\nDo you want me to convert it to grayscale for you so you can continue?', numberOfColorChannels); button = questdlg(promptMessage, 'Continue', 'Convert and Continue', 'Cancel', 'Convert and Continue');
if strcmp(button, 'Cancel') fprintf(1, 'Finished running micellesDemo.m.\n'); return;
end
originalImage = rgb2gray(originalImage);
end
h1=figure(1);
subplot(2, 2, 1);
imshow(originalImage); set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
[pixelCount, grayLevels] = imhist(originalImage);
subplot(2, 2, 2); bar(pixelCount);
title('Histogram of original image', 'FontSize', captionFontSize); xlim([0 grayLevels(end)]);
grid on;
thresholdValue = 100; binaryImage = originalImage > thresholdValue;
binaryImage = imfill(binaryImage, 'holes');
% Show the threshold as a vertical red bar on the histogram. hold on;
maxYValue = ylim; line([thresholdValue, thresholdValue], maxYValue, 'Color', 'r');
annotationText = sprintf('Thresholded at %d gray levels', thresholdValue);
text(double(thresholdValue + 5), double(0.5 * maxYValue(2)), annotationText, 'FontSize', 10, 'Color', [0 .5 0]); text(double(thresholdValue - 70), double(0.94 * maxYValue(2)), 'Background', 'FontSize', 10, 'Color', [0 0 .5]); text(double(thresholdValue + 50), double(0.94 * maxYValue(2)), 'Foreground', 'FontSize', 10, 'Color', [0 0 .5]);
imshow(binaryImage); title('Image converted into Binary after thresholding', 'FontSize', captionFontSize);
labeledImage = bwlabel(binaryImage, 8); subplot(2, 2, 3); imshow(labeledImage, []);
title('Micelle groups', 'FontSize', captionFontSize); micellMeasurements = regionprops(labeledImage, originalImage, 'all'); numberOfmicell = size(micellMeasurements, 1);
subplot(2, 2, 4); imshow(originalImage);
title('Outlines, from bwboundaries()', 'FontSize', captionFontSize); axis image;
hold on; boundaries = bwboundaries(binaryImage); numberOfBoundaries = size(boundaries, 1); for k = 1 : numberOfBoundaries thisBoundary = boundaries{k}; plot(thisBoundary(:,2), thisBoundary(:,1), 'g', 'LineWidth', 2); end; hold off;
textFontSize = 14; % Used to control size of "micelle number" labels put atop the image.
labelShiftX = -7;
micelleECD = zeros(1, numberOfmicell);
fprintf(1,'micelle # Mean Intensity Area Perimeter Centroid Diameter\n');
for k = 1 : numberOfmicell
thismicellesPixels = micellMeasurements(k).PixelIdxList;
meanGL = mean(originalImage(thismicellesPixels));
meanGL2008a = micellMeasurements(k).MeanIntensity;
micelleArea = micellMeasurements(k).Area;
micellePerimeter = micellMeasurements(k).Perimeter;
micelleCentroid = micellMeasurements(k).Centroid;
micelleECD(k) = sqrt(4 * micelleArea / pi);
fprintf(1,'#%2d %17.1f %11.1f %8.1f %8.1f %8.1f % 8.1f\n', k, meanGL, micelleArea, micellePerimeter, micelleCentroid, micelleECD(k));
% text(micelleCentroid(1) + labelShiftX, micelleCentroid(2), num2str(k), 'FontSize', textFontSize, 'FontWeight', 'Bold');
text(micelleCentroid(1) + labelShiftX, micelleCentroid(2), num2str(k), 'FontSize', textFontSize, 'FontWeight', 'Bold');
end
if you find my answer useful would you please mark it as Accepted Answer by clicking on the ACCEPT ANSWER button?
thanks in advance for time and attention
John BG
7 Kommentare
John BG
am 14 Jan. 2017
Regarding your second question, when using 4 separate figures, one can appreciate the grey shading you mention.
The function subplot may be useful to have a quick look, but with the thorough image analysis you perform, I recommend you split the images into 4 different figures. Then you can resize them and details like the grey shading missed in the decimated subplot is clearly present in figure 3:
I have already replaced all subplots with figure(i), just run the following:
format long g;
format compact; captionFontSize = 14;
FileName = 'dirty_water.jpg'; originalImage = imread(FileName);
% Checks for grayscale images
[rows, columns, numberOfColorChannels] = size(originalImage);
if numberOfColorChannels > 1 promptMessage = sprintf('Your image file has %d color channels.\nThis demo was designed for grayscale images.\nDo you want me to convert it to grayscale for you so you can continue?', numberOfColorChannels); button = questdlg(promptMessage, 'Continue', 'Convert and Continue', 'Cancel', 'Convert and Continue');
if strcmp(button, 'Cancel') fprintf(1, 'Finished running micellesDemo.m.\n'); return;
end
originalImage = rgb2gray(originalImage);
end
h1=figure(1);
figure(1);
% subplot(2, 2, 1);
imshow(originalImage); set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
[pixelCount, grayLevels] = imhist(originalImage);
figure(2);
% subplot(2, 2, 2);
bar(pixelCount);
title('Histogram of original image', 'FontSize', captionFontSize); xlim([0 grayLevels(end)]); grid on;
thresholdValue = 100; binaryImage = originalImage > thresholdValue;
binaryImage = imfill(binaryImage, 'holes');
maxYValue = ylim; line([thresholdValue, thresholdValue], maxYValue, 'Color', 'r'); % Show the threshold as a vertical red bar on the histogram. hold on;
annotationText = sprintf('Thresholded at %d gray levels', thresholdValue);
text(double(thresholdValue + 5), double(0.5 * maxYValue(2)), annotationText, 'FontSize', 10, 'Color', [0 .5 0]); text(double(thresholdValue - 70), double(0.94 * maxYValue(2)), 'Background', 'FontSize', 10, 'Color', [0 0 .5]); text(double(thresholdValue + 50), double(0.94 * maxYValue(2)), 'Foreground', 'FontSize', 10, 'Color', [0 0 .5]);
imshow(binaryImage); title('Image converted into Binary after thresholding', 'FontSize', captionFontSize);
labeledImage = bwlabel(binaryImage, 8);
figure(3)
% subplot(2, 2, 3);
imshow(labeledImage, []);
title('Micelle groups', 'FontSize', captionFontSize); micellMeasurements = regionprops(labeledImage, originalImage, 'all'); numberOfmicell = size(micellMeasurements, 1);
figure(4);
% subplot(2, 2, 4);
imshow(originalImage);
title('Outlines, from bwboundaries()', 'FontSize', captionFontSize); axis image; hold on;
boundaries = bwboundaries(binaryImage); numberOfBoundaries = size(boundaries, 1); for k = 1 : numberOfBoundaries thisBoundary = boundaries{k}; plot(thisBoundary(:,2), thisBoundary(:,1), 'g', 'LineWidth', 2); end; hold off;
textFontSize = 14; % Used to control size of "micelle number" labels put atop the image.
labelShiftX = -7;
micelleECD = zeros(1, numberOfmicell);
fprintf(1,'micelle # Mean Intensity Area Perimeter Centroid Diameter\n');
for k = 1 : numberOfmicell
thismicellesPixels = micellMeasurements(k).PixelIdxList;
meanGL = mean(originalImage(thismicellesPixels));
meanGL2008a = micellMeasurements(k).MeanIntensity;
micelleArea = micellMeasurements(k).Area;
micellePerimeter = micellMeasurements(k).Perimeter;
micelleCentroid = micellMeasurements(k).Centroid;
micelleECD(k) = sqrt(4 * micelleArea / pi);
fprintf(1,'#%2d %17.1f %11.1f %8.1f %8.1f %8.1f % 8.1f\n', k, meanGL, micelleArea, micellePerimeter, micelleCentroid, micelleECD(k));
text(micelleCentroid(1) + labelShiftX, micelleCentroid(2), num2str(k), 'FontSize', textFontSize, 'FontWeight', 'Bold');
end
Image Analyst
am 14 Jan. 2017
What is this image? It look like foam on a sea. If so, is the original image in color? If so you might have better luck doing color segmentation than using a gray scale version of the image. If it's a color image, post it and I'll show you the 3D color gamut.
Weitere Antworten (0)
Siehe auch
Produkte
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!