How to accurately process multiple frames in a video file using for and while loops

I am interested in tracking a white horizontal line that slowly moves up a semicircle (bottom to top) over time. In my code: I import my video > read the frames > crop them and place them into a cell that contains each frame of the freezing droplet. I then select the same column in each frame and wish to analyze the movement of the freezing droplet over time (or frames).
The problem I am having is my code doesn't read all of the rows in each frame completely. It looks like it stops at the last white pixel. I know this because the cell I am building through my for loop (variable A) has different sized matrices in them. Some matrices have more amounts of rows than others. While what I want is for all matrices to have 230 rows (the max height of the droplet) so that I know the exact location of the freezing line in that frame.
I have attached the variable (Crop1) that contains all 700 of the frames that I want to be observing. The following is my code:
nstart = 260;
nend = 700;
load('Crop1.mat')
middle1 = 243;
for t = nstart:nend % nstart and nend are the first and last frames to be observed respectively
i = 1;
while i<230 % 230 is the max height of the droplet
if Crop1{t}(i,middle1) == 1 %Crop1 is a cell made of up of video frames
A{t}(i,1) = Crop1{t}(i,middle1);
%i = 230;
end
i = i + 1;
end
I{t} = [A{t},;];
end
The end goal of this is to obtain a cell that consists of 700 (which is the amount of frames) matrices. These matrices need to have only 1 column and 230 rows. Then, I will be able to pinpoint the location of the freezing line in each matrix and plot it against time.

 Accepted Answer

7 Comments

Thanks, but I already know how to do that, in fact I am doing that in my code. The frames don't need to be extracted, they need to be analyzed properly
It's kind of hard for us to suggest an algorithm without seeing the video. Would you know how to process my video if I just told you I need to process it without showing you what is in my video?
Yes you are right, you cant really help when there is no source file! I have attached the variable (Crop1.mat) that acts as my frames from my video. If you download this variable and then run my updated code you should be able to see how the matrices in variable A have different amounts of rows in them. Thanks!
I still have no idea what to do. Here is the first non-empty frame and the last frame:
I have no idea where the freezing line is, other than maybe it's the flat bottom of the semicircle. But it doesn't seem to move substantially. I don't know what you want to measure. Here is my code so far:
s = load('crop1.mat')
crop1 = s.Crop1;
numCells = length(crop1)
for k = 1 : numCells
thisCell = crop1{k};
if ~isempty(thisCell)
imshow(thisCell);
caption = sprintf('%d of %d', k, numCells);
title(caption);
drawnow;
end
end
The freezing line moves up the frames and has a strong presence during the 400 to 650 frames of the sequence. If you run the following code:
for i = nstart:1:nend
imshow(Crop1{1,i})
end
You will see the freezing line as it moves up the center of the semicircle. It disappears near the end of the sequence at the top. If you observe the movement of the line, you will see that under it is black but above it there is distortion. I want my code to be able to start at row 0 and scan up to the row that contains the freezing line. Once it reaches the freezing line, I want the code to stop and place it's location (like row number) or even the whole matrix into a cell. By the end of this I should have a matrix for each frame which will be in a cell. Then, I can plot the exact positioning of the line vs numberofFrames and get the behavior of the freezing process.
In my original code, I simplified the process by picking a single column in my frames (called middle1) and analyzing each frame only at this column. The problem I was having was that my code wouldn't stop at the freezing line like I wanted it to, it would stop at the last white pixel. This lead to matrices of different sizes. The end result is to have matrices that look like this all in a cell:
  • [0
  • 0
  • 0
  • 1 ]
  • [0
  • 0
  • 1
  • 0 ]
  • [0
  • 1
  • 0
  • 0 ]
  • [1
  • 0
  • 0
  • 0 ]
Or to have a matrix that contains the row number of the freezing line as you read each frame.
It could be better and more robust, but this is what I could do in a few minutes off the top of my head:
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;
s = load('crop1.mat')
crop1 = s.Crop1;
startTime = tic; % Start timer.
numberOfCells = length(crop1)
freezingLine = zeros(1, numberOfCells);
for k = 1 : numberOfCells
thisCell = crop1{k};
if ~isempty(thisCell)
subplot(2, 2, 1);
imshow(thisCell);
axis on;
caption = sprintf('Frame %d of %d', k, numberOfCells);
title(caption, 'FontSize', fontSize);
% Extract columns 200-300
croppedImage = thisCell(1:200, 200:300);
subplot(2, 2, 2);
imshow(croppedImage);
axis on;
title(caption, 'FontSize', fontSize);
% Get the bottom most pixel
[rows, columns] = size(croppedImage);
bottomLine = zeros(1, columns);
for col = 1 : columns
bottomLine(col) = find(croppedImage(:, col), 1, 'last');
end
subplot(2, 2, 3);
plot(bottomLine, 'b-', 'LineWidth', 2);
ylim([1, rows]);
xlim([1, columns]);
title('Bottom Pixels', 'FontSize', fontSize);
xlabel('Column', 'FontSize', fontSize);
ylabel('Row', 'FontSize', fontSize);
grid on;
% Throw out outliers by looking at the median absolute deviation.
medianValue = median(bottomLine);
mad = bottomLine - medianValue;
goodIndexes = mad <= 3; % Good locations have a mad of less than or equal to 3.
% Find the mean of the good indexes.
freezingLine(k) = mean(bottomLine(goodIndexes));
subplot(2, 2, 4);
plot(freezingLine, 'b-', 'LineWidth', 2);
grid on;
title('Freezing Line Row', 'FontSize', fontSize);
xlabel('Frame', 'FontSize', fontSize);
ylabel('Row', 'FontSize', fontSize);
drawnow;
end
end
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0, 0.04, 1, 0.96]);
% Stop timer
elapsedTime = toc(startTime);
fprintf('Elapsed time = %.1f seconds\n', elapsedTime);
You can see the "good" part, where the slanted line in the lower right plot it. You could find that somehow and extract it out from the rest of the plot. I didn't have time for that and will leave it to you. Let me know what you think.
Yes, your solution works quite nicely! I think at this point I just have to work on a better method of processing my image, thanks!

Sign in to comment.

More Answers (0)

Asked:

on 18 Feb 2018

Edited:

on 20 Feb 2018

Community Treasure Hunt

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

Start Hunting!