How to extract frames of a video
Show older comments
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.
Accepted Answer
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
Beenish Mazhar
on 22 Sep 2012
kirk
on 15 Apr 2013
i am using the above code but getting the following error
Undefined function or variable "ME".
Error in ==> videotoframes at 195 catch ME
Image Analyst
on 15 Apr 2013
You probably forgot to put the "try" line in.
Parth Batra
on 23 May 2014
Thanks it was a great help.
John
on 14 Aug 2014
Image Analyst, I know this is an old post, but I could some help from you if you wouldn't mind...
I want to do something similar to what your above code (and what the overall thread) is talking about.
I want to import an mp4 video. Have the user pick which video they want with the uigetfile command. Break the video back down into individual frames. Save the frames this way: the videos are in a root folder, I want to create a new folder in this root folder where the videos are, and call the folder, for example, "Video1-Frames" or something along those lines. Then save the individual frames into that folder. I'm not sure how many frames there could be, but I'd like to plan for 10,000 or more, but definitely under 100,000. So the frames would need to be saved named as such: Video1_Frame00001, Video1_Frame00002, Video1_Frame00003 all the way to however many individual frames there are in the video. And I'd like the individual frames to be an image file (.tiff, .gif. .jpg; doesn't matter... whichever is smaller) and I'd like them to be the same resolution as the original video.
I know this is alot, but can you or someone else help?
Image Analyst
on 14 Aug 2014
What about the code doesn't work for doing that? The first part of the code does that. If you don't want the second half of the code where it reads back in the individual image files and creates a movie, then just delete that part. I'm attaching the latest version I have, in case I've made changes to what's posted since then (not sure if I have, but just in case).
John
on 14 Aug 2014
The code will not find any movie files with the ".mp4" extention. Seems to be catered to ones with the ".avi" extension.
Image Analyst
on 14 Aug 2014
So change it John. The filename is hard coded in there to be one of the standard video demos that ship with MATLAB:
movieFullFileName = fullfile(folder, 'traffic.avi');
Just change it to whatever you want. It can be an mp4 file or whatever.
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
krishna Chauhan
on 20 Jul 2022
This is not working in my case.
obj = VideoReader('k.avi');
vid = read(obj);
But I am getting nothing inside the obj.NumFrames
It is 0.
Can any one guide please?
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
1 vote
How can I add a legend like this Redline - meanRed, Blueline - meanBlue, ... to the subplot(2, 2, 2)?
2 Comments
Sushil Sharma
on 12 Dec 2019
legend('real angle', 'estimate angle')
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
on 21 Nov 2024
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);
msp
on 28 Apr 2013
0 votes
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
Ely Raz
on 16 Dec 2019
0 votes
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
on 21 Nov 2024
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
Categories
Find more on Get Started with Computer Vision Toolbox in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!