How to extract frames of a video
299 views (last 30 days)
Show older comments
Beenish Mazhar
on 22 Sep 2012
Edited: Walter Roberson
about 4 hours ago
Hi everyone! How can I extract frames of a video in matlab if I have used mmreader to read the video.I have used frame2im command but its not working.
2 Comments
chao dong
on 30 May 2016
I also need to extract pictures from video files, but it seems to me that format is critical towards this process.
Accepted Answer
Walter Roberson
on 22 Sep 2012
obj = mmreader(FileName);
video = obj.read();
Then, frame #K is video(:,:,:,K)
14 Comments
Walter Roberson
on 17 Mar 2021
NumberOfFrames was historically a correct property names; it was since replaced with NumFrames . https://www.mathworks.com/matlabcentral/answers/250033-number-of-frames-in-video-file-with-matlab-2015b#answer_196870
The difference between NumberOfFrames and NumFrames is that NumberOfFrames involved MATLAB scanning the entire file at the time the VideoReader object was created, so NumberOfFrames was an accurate frame count, whereas NumFrames was an estimated count that did not involve scanning the entire stream. This made NumFrames much more efficient to get started with.
Using duration * Framerate is only an estimate, and fails under a couple of circumstances:
- variable frame rate movies
- if the stored FrameRate has been rounded, as is common for NTSC (people often specify 30 fps, or 29.9, or (when they try to be more accurate) 29.97 fps, but the true frame rate is slightly higher than 29.97)
- Frame rates are stored in several file formats as the ratio of two integers, but the range of values allowed does not permit sufficient precision to be frame accurate after longer sequences
- embedded devices are permitted by the standards to use frame rate calculations using limited precision, so that they do not need a full floating point cores, and can use much much less processor intensive fixed-point cores instead
Because of this, if you need an accurate count of frames, you need to count the frames instead of calculating how many there are.
Hazem El-Alfy
on 17 Mar 2021
Great rebuttal of my earlier comment. I would rather not delete it for others to understand how not to address this issue.
More Answers (8)
Image Analyst
on 22 Sep 2012
See my demo for extracting and measuring an AVI file (the standard MATLAB rhinos.avi movie):
% Demo macro to extract frames and get frame means from an avi movie
% and save individual frames to separate image files.
% Also computes the mean gray value of the color channels.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
imtool close all; % Close all imtool figures.
clear; % Erase all existing variables.
workspace; % Make sure the workspace panel is showing.
fontSize = 14;
% Change the current folder to the folder of this m-file.
% (The line of code below is from Brett Shoelson of The Mathworks.)
if(~isdeployed)
cd(fileparts(which(mfilename)));
end
% Open the rhino.avi demo movie that ships with MATLAB.
folder = fullfile(matlabroot, '\toolbox\images\imdemos');
movieFullFileName = fullfile(folder, 'rhinos.avi');
% Check to see that it exists.
if ~exist(movieFullFileName, 'file')
strErrorMessage = sprintf('File not found:\n%s\nYou can choose a new one, or cancel', movieFullFileName);
response = questdlg(strErrorMessage, 'File not found', 'OK - choose a new movie.', 'Cancel', 'OK - choose a new movie.');
if strcmpi(response, 'OK - choose a new movie.')
[baseFileName, folderName, FilterIndex] = uigetfile('*.avi');
if ~isequal(baseFileName, 0)
movieFullFileName = fullfile(folderName, baseFileName);
else
return;
end
else
return;
end
end
try
movieInfo = aviinfo(movieFullFileName)
mov = aviread(movieFullFileName);
% movie(mov);
% Determine how many frames there are.
numberOfFrames = size(mov, 2);
numberOfFramesWritten = 0;
% Prepare a figure to show the images in the upper half of the screen.
figure;
screenSize = get(0, 'ScreenSize');
newWindowPosition = [1 screenSize(4)/2 - 70 screenSize(3) screenSize(4)/2];
set(gcf, 'Position', newWindowPosition); % Maximize figure.
% set(gcf, 'Position', get(0,'Screensize')); % Maximize figure.
% Ask user if they want to write the individual frames out to disk.
promptMessage = sprintf('Do you want to save the individual frames out to individual disk files?');
button = questdlg(promptMessage, 'Save individual frames?', 'Yes', 'No', 'Yes');
if strcmp(button, 'Yes')
writeToDisk = true;
% Extract out the various parts of the filename.
[folder, baseFileName, extentions] = fileparts(movieFullFileName);
% Make up a special new output subfolder for all the separate
% movie frames that we're going to extract and save to disk.
% (Don't worry - windows can handle forward slashes in the folder name.)
folder = pwd; % Make it a subfolder of the folder where this m-file lives.
outputFolder = sprintf('%s/Movie Frames from %s', folder, baseFileName);
% Create the folder if it doesn't exist already.
if ~exist(outputFolder, 'dir')
mkdir(outputFolder);
end
else
writeToDisk = false;
end
% Loop through the movie, writing all frames out.
% Each frame will be in a separate file with unique name.
meanGrayLevels = zeros(numberOfFrames, 1);
meanRedLevels = zeros(numberOfFrames, 1);
meanGreenLevels = zeros(numberOfFrames, 1);
meanBlueLevels = zeros(numberOfFrames, 1);
for frame = 1 : numberOfFrames
% Extract the frame from the movie structure.
thisFrame = mov(frame).cdata;
% Display it
hImage = subplot(1,2,1);
image(thisFrame);
axis square;
caption = sprintf('Frame %4d of %d.', frame, numberOfFrames);
title(caption, 'FontSize', fontSize);
drawnow; % Force it to refresh the window.
% Write the image array to the output file, if requested.
if writeToDisk
% Construct an output image file name.
outputBaseFileName = sprintf('Frame %4.4d.png', frame);
outputFullFileName = fullfile(outputFolder, outputBaseFileName);
% Stamp the name and frame number onto the image.
% At this point it's just going into the overlay,
% not actually getting written into the pixel values.
text(5, 15, outputBaseFileName, 'FontSize', 20);
% Extract the image with the text "burned into" it.
frameWithText = getframe(gca);
% frameWithText.cdata is the image with the text
% actually written into the pixel values.
% Write it out to disk.
imwrite(frameWithText.cdata, outputFullFileName, 'png');
end
% Calculate the mean gray level.
grayImage = rgb2gray(thisFrame);
meanGrayLevels(frame) = mean(grayImage(:));
% Calculate the mean R, G, and B levels.
meanRedLevels(frame) = mean(mean(thisFrame(:, :, 1)));
meanGreenLevels(frame) = mean(mean(thisFrame(:, :, 2)));
meanBlueLevels(frame) = mean(mean(thisFrame(:, :, 3)));
% Plot the mean gray levels.
hPlot = subplot(1,2,2);
hold off;
plot(meanGrayLevels, 'k-', 'LineWidth', 2);
hold on;
plot(meanRedLevels, 'r-');
plot(meanGreenLevels, 'g-');
plot(meanBlueLevels, 'b-');
% Put title back because plot() erases the existing title.
title('Mean Gray Levels', 'FontSize', fontSize);
if frame == 1
xlabel('Frame Number');
yLabel('Gray Level');
% Get size data later for preallocation if we read
% the movie back in from disk.
[rows columns numberOfColorChannels] = size(thisFrame);
end
% Update user with the progress. Display in the command window.
if writeToDisk
progressIndication = sprintf('Wrote frame %4d of %d.', frame, numberOfFrames);
else
progressIndication = sprintf('Processed frame %4d of %d.', frame, numberOfFrames);
end
disp(progressIndication);
% Increment frame count (should eventually = numberOfFrames
% unless an error happens).
numberOfFramesWritten = numberOfFramesWritten + 1;
end
% Alert user that we're done.
if writeToDisk
finishedMessage = sprintf('Done! It wrote %d frames to folder\n"%s"', numberOfFramesWritten, outputFolder);
else
finishedMessage = sprintf('Done! It processed %d frames of\n"%s"', numberOfFramesWritten, movieFullFileName);
end
disp(finishedMessage); % Write to command window.
uiwait(msgbox(finishedMessage)); % Also pop up a message box.
% Exit if they didn't write any individual frames out to disk.
if ~writeToDisk
return;
end
% Ask user if they want to read the individual frames from the disk,
% that they just wrote out, back into a movie and display it.
promptMessage = sprintf('Do you want to recall the individual frames\nback from disk into a movie?\n(This will take several seconds.)');
button = questdlg(promptMessage, 'Recall Movie?', 'Yes', 'No', 'Yes');
if strcmp(button, 'No')
return;
end
% Read the frames back in, and convert them to a movie.
% I don't know of any way to preallocate recalledMovie.
for frame = 1 : numberOfFrames
% Construct an output image file name.
outputBaseFileName = sprintf('Frame %4.4d.png', frame);
outputFullFileName = fullfile(outputFolder, outputBaseFileName);
% Read the image in from disk.
thisFrame = imread(outputFullFileName);
% Convert the image into a "movie frame" structure.
recalledMovie(frame) = im2frame(thisFrame);
end
% Get rid of old image and plot.
delete(hImage);
delete(hPlot);
% Create new axes for our movie.
subPlot(1, 3, 2);
axis off; % Turn off axes numbers.
title('Movie recalled from disk', 'FontSize', fontSize);
% Play the movie in the axes.
movie(recalledMovie);
% Note: if you want to display graphics or text in the overlay
% as the movie plays back then you need to do it like I did at first
% (at the top of this file where you extract and imshow a frame at a time.)
msgbox('Done with this demo!');
catch ME
% Some error happened if you get here.
stError = lasterror;
strErrorMessage = sprintf('Error extracting movie frames from:\n\n%s\n\nError: %s\n\n)', movieFullFileName, stError.message);
uiwait(msgbox(strErrorMessage));
end
10 Comments
John
on 14 Aug 2014
My mistake... The drop down that shows up when searching for the file was not set to "all files" but was set to "avi" and I didn't realize it.
But, I did change the code to adapt to the location of the file. I may be a little slow sometimes, but that's one thing I did catch when looking through the code. :)
LaraS
on 23 Feb 2024
Hi, I'd like to adapt this so I can perform background subtraction on two channels simultaneously, using tophat filtering. It seems like when I try to do this I mess up the code because the binarized plot basically returns empty while the adaptive background is all black. Any thoughts on how I can incorporate this?
Sushil Sharma
on 15 Oct 2019
Upadte answer
In the lestest veriosn of matlab, we have to use VideoReader instead of mmreader,then you are able to convert any video file into a frames
Here the simple of code to get the frames
%% Change .avi format to images frames
obj = VideoReader('test2.avi');
vid = read(obj);
frames = obj.NumberOfFrames;
for x = 1 : frames
imwrite(vid(:,:,:,x),strcat('frame-',num2str(x),'.png'));
end
3 Comments
Image Analyst
on 20 Jul 2022
@krishna Chauhan looks like your file may be empty. Can you attach it in a new question? For some reason they changed the number of frames name from NumberOfFrames to NumFrames. Make sure you're using the right one. I'm attaching my latest movie demos.
If you have any more questions, then, in your new discussion thread, attach your data and code to read it in with the paperclip icon after you read this:
Walter Roberson
on 20 Jul 2022
NumFrames has a slightly different semantics than NumberOfFrames . The older NumberOfFrames was initialized when the file was opened, by reading the entire file to get the exact number of frames. The newer NumFrames is estimated at the time the video is opened, based upon file size and nominal frame rate, but will be corrected if you read to end of video.
NumberOfFrames was trustable but slow and was overhead that was incurred for every video even when you did not need it.
NumFrames is not trustable but is fast; if you need to know the exact actual number of frames you have to read the file through.
dan kin
on 12 Dec 2019
How can I add a legend like this Redline - meanRed, Blueline - meanBlue, ... to the subplot(2, 2, 2)?
2 Comments
Image Analyst
on 12 Dec 2019
See my attached demo, ExtractMovieFrames.m.
You can also use text() instead of legend() if you want more precise control over where the legend appears.
MathWorks Computer Vision Toolbox Team
about 4 hours ago
MMreader has been deprecated. VideoReader is now recommended.
v = VideoReader("xylophone_video.mp4");
% Read next available frame
frame = readFrame(v);
% Read Nth frame
N = 5;
frameN = read(v,N);
0 Comments
msp
on 28 Apr 2013
how to extract only key frames from the video ??
2 Comments
ameet kumar
on 30 Jan 2016
There is an error when I used the 'movie2avi' it cannot generate avi file in matlab R2013 so kindly help me what can I do?
Walter Roberson
on 30 Jan 2016
We need to know the error message. But you already asked this as a Question so the discussion should go there
Ameni chetouane
on 27 Jun 2019
I have read frames with VideoReader,but i don'i get the exact number of frames that contain the video.
the number of frames of the video is 400 but readFrame return only 200 frames.
Does any one have solution to this problem?
clear
clc
% Set up video reader and player
videoFile = 'copie2.avi';
videoReader = VideoReader(videoFile);
iStop = []; % Stop the frame display if this is not empty
fps = get(videoReader, 'FrameRate');
disp(fps); % the fps is correct: it's the same declared in the video file properties
t=1;
while hasFrame(videoReader)& isempty(iStop)
%%for i=0:videoReader.Duration-1
%% videoReader.CurrentTime=i;
fr(:,:,:,t)=readFrame(videoReader);
frGray(:,:,t)=rgb2gray(readFrame(videoReader));
t=t+1;
iStop = input('0 to stop, return to continue');
end
0 Comments
Ely Raz
on 16 Dec 2019
How can I add the possibility to select a ROI in Image Analyst script and analyzed it?
1 Comment
Image Analyst
on 16 Dec 2019
You can call imcrop() if you want a rectangular sub-image. If you want an irregularly-shaped region, see my attached demos.
Aayush Gupta
on 23 May 2021
Edited: Walter Roberson
on 23 May 2021
v=videoReader('filename.mp4')
%to read all the frames
frames=read(v)
% for reading any particular nth frame you can use read(v, n) or for reading a set of frames from 1 to 50 use read(v, [1,50])
%Note that these frames are particular 4Dimebsional uint8 code of a block
% to form an image or a still out from the frames use the code given below
num=v.NumberOfFrames
images=reshape(frames, 360, 540, 3, num)
%here using the command imshow(frames(:, :, :, 1)) get the dimensions of one particular still which is (360x540x3) in my case
%Now images will be the collection of all stills present in the video filename.mp4
%use imshow(images(:, :, :, 1)) to view the first still
1 Comment
Walter Roberson
on 23 May 2021
Edited: Walter Roberson
3 minutes ago
If you have done frames=read(v) then you can use
num = size(frames,4);
There is no benefit to doing the reshape(): it only leads to problems if your frames are not each 360 x 540 x 3. Just using read() is enough to get the frames as H x W x 3 x num
See Also
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!