Image processing Granular Flow

9 views (last 30 days)
I want to execute image processing for a numerous set of frames (two consecutive photos shown below, similarly several photographs were collected at equal time intervals) and plot the velocity variation across the container's base. The idea is to create a grid domain and then analyse the region of interest, i.e. the bottom region, plot velocity of particles near that region, and determine mass flow rate from openings). can anyone help me if they have done similar kind of work. It is granular flow problem.

Accepted Answer

Image Analyst
Image Analyst on 7 Nov 2021
If you want only the stuff below the line 677, try this. You can then sum up the area of the image with nnz() and divide by the area of one particle if you want a count of particles.
% 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;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
fileName = 'red grains.png';
grayImage = imread(fileName);
% 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 blue channel (so the magenta lines will be white).
grayImage = grayImage(:, :, 3);
end
% Crop off white border/frame.
grayImage = grayImage(37:732, 274:751);
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage, []);
impixelinfo;
axis('on', 'image');
title('Original Image', 'FontSize', fontSize, 'Interpreter', 'None');
hold on
drawnow;
% Maximize window.
g = gcf;
g.WindowState = 'maximized'
drawnow;
%--------------------------------------------------------------------------------------------------------
% Compute binary image
binaryImage = ~imbinarize(grayImage);
subplot(2, 2, 2);
imshow(binaryImage);
title('Initial Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
[rows, columns] = size(binaryImage);
binaryImage = imfill(binaryImage, 'holes');
binaryImage = bwareafilt(binaryImage, 1);
% Erase lines 677 and above
binaryImage(1:677, :) = false;
subplot(2, 2, 3);
imshow(binaryImage);
title('Final Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;

More Answers (4)

Image Analyst
Image Analyst on 6 Nov 2021
Edited: Image Analyst on 6 Nov 2021
Try this
  1. Take the blue channel since it has the most contrast.
  2. Threshold the blue channel image with imbinarize()
  3. Fill holes with imfill()
  4. Call bwareafilt() to take the largest blob.
  5. Scan across the image using find() to find the top row in each column.
  6. From the distance the top row moved from frame #1, you can compute the velocity and area gain for each column.
Something like
% 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;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
fileName = 'red grains.png';
grayImage = imread(fileName);
% 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 blue channel (so the magenta lines will be white).
grayImage = grayImage(:, :, 3);
end
% Crop off white border/frame.
grayImage = grayImage(37:732, 274:751);
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 3, 1);
imshow(grayImage, []);
impixelinfo;
axis('on', 'image');
title('Original Image', 'FontSize', fontSize, 'Interpreter', 'None');
hold on
drawnow;
% Maximize window.
g = gcf;
g.WindowState = 'maximized'
drawnow;
%--------------------------------------------------------------------------------------------------------
% Compute .
binaryImage = ~imbinarize(grayImage);
subplot(2, 3, 2);
imshow(binaryImage);
title('Initial Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
[rows, columns] = size(binaryImage);
binaryImage = imfill(binaryImage, 'holes');
binaryImage = bwareafilt(binaryImage, 1);
topRows = nan(1, columns);
for col = 1 : columns
tr = find(binaryImage(:, col), 1, 'first');
if ~isempty(tr)
topRows(col) = tr;
end
end
subplot(2, 3, 3);
imshow(binaryImage);
title('Final Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Display the image.
subplot(2, 3, 4);
plot(topRows, 'b-', 'LineWidth', 2);
axis ij;
grid on;
title('Top Rows', 'FontSize', fontSize, 'Interpreter', 'None');
hold on
drawnow;

yanqi liu
yanqi liu on 8 Nov 2021
clc; clear all; close all;
im = imread('https://ww2.mathworks.cn/matlabcentral/answers/uploaded_files/791594/Pic10101.png');
jm = rgb2hsv(im);
jm = mat2gray(jm(:,:,2));
bw = im2bw(jm, 0.8);
rs = sum(bw, 2);
ind = find(rs<max(rs)*0.5);
ind2 = find(diff(ind)>1e1);
if ~isempty(ind2)
ind3 = ind(ind2(1)+1);
else
ind3 = [];
end
figure; imshow(im, []);
if ~isempty(ind3)
hold on; plot([1,size(im,2)],[ind3 ind3],'g-','LineWidth',2);
end
figure; imshow(bw, []);
if ~isempty(ind3)
hold on; plot([1,size(im,2)],[ind3 ind3],'g-','LineWidth',2);
end

Image Analyst
Image Analyst on 8 Nov 2021
Yash:
Here is an extended version that automatically finds the bottom of the container (line 677) and sums up the area (787 pixels) of the particles streaming through the bottom opening of the container, and computes the number of particles (66) assuming an area of 12 pixels per particle.
% 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;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
fileName = 'red grains.png';
grayImage = imread(fileName);
% 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 blue channel (so the magenta lines will be white).
grayImage = grayImage(:, :, 3);
end
% Crop off white border/frame.
grayImage = grayImage(37:732, 274:751);
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage, []);
impixelinfo;
axis('on', 'image');
title('Original Image', 'FontSize', fontSize, 'Interpreter', 'None');
hold on
drawnow;
% Maximize window.
g = gcf;
g.WindowState = 'maximized'
g.NumberTitle = 'off';
g.Name = 'Demo By Image Analyst'
drawnow;
%--------------------------------------------------------------------------------------------------------
% Compute binary image
binaryImage = ~imbinarize(grayImage);
subplot(2, 2, 2);
imshow(binaryImage);
axis('on', 'image');
impixelinfo;
title('Initial Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
[rows, columns] = size(binaryImage);
binaryImage = imfill(binaryImage, 'holes');
binaryImage = bwareafilt(binaryImage, 1);
% Find the bottom
verticalProfile = rescale(sum(binaryImage, 2), 0, 1);
subplot(2, 2, 3);
plot(verticalProfile, 'b-', 'LineWidth', 2)
xlabel('Row', 'FontSize', fontSize, 'Interpreter', 'None');
ylabel('Normalized Sum', 'FontSize', fontSize, 'Interpreter', 'None');
% Find the last line (row) where the signal falls below 0.4
lastLine = find(verticalProfile > 0.4, 1, 'last')
yline(0.1, 'Color','r', 'LineWidth',2)
xline(lastLine, 'Color','r', 'LineWidth',2)
caption = sprintf('Average Vertical Profile. Bottom Line = %d', lastLine);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
grid on;
% Erase lines lastLine and above
binaryImage(1:lastLine, :) = false;
% Compute total area (pixel count) using nnz.
totalArea = nnz(binaryImage)
% Compute the number of particles assuming the area of a single particle is 12 pixels.
particleCount = totalArea / 12;
subplot(2, 2, 4);
imshow(binaryImage);
axis('on', 'image');
caption = sprintf('Final Binary Image.\nArea = %d pixels. Number of Particles = %.1f', totalArea, particleCount);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;

Yash Bhati
Yash Bhati on 7 Nov 2021
I just want to look at this part of the image so that I can calculate the mass flow rate through the opening at the bottom. What I thought was to calculate the net flow rate by analysing how many granular particels pass through this grid region and then subtracting images to determine how many particels entered the zone and how many exited. I'm not sure what exactly is represented by the graphs in your code; if possible, please elaborate so that I can grasp what's going on.
.

Products


Release

R2021b

Community Treasure Hunt

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

Start Hunting!