How to extract frames of a video

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

how to extract only key frames from the video ??
I also need to extract pictures from video files, but it seems to me that format is critical towards this process.

Sign in to comment.

 Accepted Answer

obj = mmreader(FileName);
video = obj.read();
Then, frame #K is video(:,:,:,K)

14 Comments

I have to read each and every frame of the video.What that obj.read()command is doing? k is my frame number so I have to make a loop for k starting from 1 to total number of frames of the video; so that I can read them one by one. but what will be the exact syntax for it.
obj = mmreader(FileName);
for k = 1 : NumberOfFrames %fill in the appropriate number
this_frame = read(obj, k);
%then do something with the frame
end
I was doing exactly the same which you have told me but I want to extract each and every frame separately( I want to view each frame in a separate figure).When I run the above mentioned code then it runs all the frames in a single figure which is not my requirement.
obj = mmreader(FileName);
for k = 1 : NumberOfFrames %fill in the appropriate number
this_frame = read(obj, k);
thisfig = figure();
thisax = axes('Parent', thisfig);
image(this_frame, 'Parent', thisax);
title(thisax, sprintf('Frame #%d', k));
end
You might notice here that the frame extraction code has not changed at all, that I have simply added some display code.
Beenish Mazhar
Beenish Mazhar on 22 Sep 2012
Edited: Beenish Mazhar on 22 Sep 2012
Thankyou now its working.Is there any command for mmreader for evaluating total number of frames of a video just like as we have for aviread command which is :
video=aviread(filename);
file=aviinfo(filename);
nFrames=file.NumFrames; %for evaluating total number of frames of video
secondly I have to crop the certain area of the frame which I have done with imcrop command and then display it with imshow() command but again its not working.I am using the command as:
I = imcrop(this_frame, [0 352 288 94]);
How Did you get the command "aviread"? When I try to use it in my code MATLAB says that it does not exist.
aviread() was in older versions of MATLAB. mmreader() and aviread() have been replaced in newer versions by VideoReader:
obj = VideoReader(FileName);
for k = 1 : NumberOfFrames %fill in the appropriate number
this_frame = readFrame(obj);
thisfig = figure();
thisax = axes('Parent', thisfig);
image(this_frame, 'Parent', thisax);
title(thisax, sprintf('Frame #%d', k));
end
Here, NumberOfFrames would be some constant according to the user needs.
If you need to process all frames, then
obj = VideoReader(FileName);
while hasFrame(obj)
this_frame = readFrame(obj);
thisfig = figure();
thisax = axes('Parent', thisfig);
image(this_frame, 'Parent', thisax);
title(thisax, sprintf('Frame #%d', k));
end
At the moment, the only reliable way to get the number of frames in a video is to loop reading frames and counting them.
If you were to look through the various documentation in current MATLAB versions, you would find that VideoReader does have a NumberOfFrames property that can be accessed after you have used VideoReader but before you have read any frames, but it turns out that the number it provides is an estimate assuming fixed framerate; the estimate is almost always wrong for variable framerate videos, and the estimate can be off by a couple of frames even for fixed framerate videos. Looping and counting is the only reliable method.
Hi, I tired the same code but got the following error. code:
obj = VideoReader('cam4v.mp4');
%obj = VideoReader(FileName);
for k = 1 : 600 %fill in the appropriate number
this_frame = readFrame(obj);
thisfig = figure();
thisax = axes('Parent', thisfig);
image(this_frame, 'Parent', thisax);
title(thisax, sprintf('Frame #%d', k));
end
Undefined function 'readFrame' for input arguments of type 'VideoReader'.
Error in videoread
(line 5) this_frame = readFrame(obj);
can anyone Help me to solve this error? my Matlab version is R2014a Thanks in advance
Hi, I run the following code for reading and playing the video also save the total no.of frames of video in the MATLAB directory.
a=VideoReader('cam4v.mp4');
for img = 1:a.NumberOfFrames;
filename=strcat('frame',num2str(img),'.jpg');
b = read(a, img);
imshow(b);
imwrite(b,filename);
end
movie(img)
i am using matlab 2014a version. hope this code may help someone. Thanks and regards
Shoba Mahan your answer is great, thanks
thank you very much
@Shoba Mohan: The correct field for the number of frames is .NumFrames according to the documentation of VideoReader() but it is not available for all video formats. Instead, it can be computed as:
nf=a.Duration*a.FrameRate; % no. of frames
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.
Great rebuttal of my earlier comment. I would rather not delete it for others to understand how not to address this issue.

Sign in to comment.

More Answers (8)

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

I have read the avi file.The only problem which I am having is how to crop the target area from the frame. When I use imcrop command I have to manually crop each frame I want to make that automatic.I just want to give a range as an argument to the imcrop command as:
I = imcrop(this_frame, [0 352 288 94]);
So that I can get the desired area automatically without doing it manually.
i am using the above code but getting the following error
Undefined function or variable "ME".
Error in ==> videotoframes at 195 catch ME
You probably forgot to put the "try" line in.
Thanks it was a great help.
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?
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).
The code will not find any movie files with the ".mp4" extention. Seems to be catered to ones with the ".avi" extension.
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.
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. :)
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?

Sign in to comment.

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

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?
@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:
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.

Sign in to comment.

dan kin
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

legend('real angle', 'estimate angle')
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.
00_Screenshot.png

Sign in to comment.

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
msp on 28 Apr 2013
how to extract only key frames from the video ??

2 Comments

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?
We need to know the error message. But you already asked this as a Question so the discussion should go there

Sign in to comment.

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
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

You can call imcrop() if you want a rectangular sub-image. If you want an irregularly-shaped region, see my attached demos.

Sign in to comment.

Aayush Gupta
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

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

Sign in to comment.

Products

Tags

Community Treasure Hunt

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

Start Hunting!