MATLAB getframe captures whatever is on screen - matlab

I am trying to create a movie from my MATLAB plot. When I call getframe, it "usually" captures the plot image, but sometimes if there is something else active on the screen (which is normal if I continue to use the computer) it captures whatever window is active. Is there another way to grab the image of the active figure?
e.g.
fig = figure;
aviobj = avifile('sample.avi','compression','None');
for i=1:t
clf(fig);
plot(...); % some arbitrary plotting
hold on;
plot(...); % some other arbitrary plotting
axis([0 50 0 50]);
aviobj = addframe(aviobj, getframe(fig));
end
aviobj = close(aviobj);

OK, found the solution; instead of
aviobj = addframe(aviobj, getframe(fig));
sending the figure handle directly to addframe is enough:
aviobj = addframe(aviobj, fig);

The Matlab people are apparently phasing out the avifile and addframe functions in future releases, replacing them with VideoWriter and writeVideo respectively. Unfortunately, this means that the accepted answer will no longer work, since writeVideo doesn't accept the figure handle as the argument.
I've played around with it a bit, and for future reference, the same thing can be accomplished using the undocumented hardcopy function. The following code works perfectly for me, with the added benefit of not even having a plot window pop up, so it does everything completely in the background:
fig = figure('Visible','off');
set(fig,'PaperPositionMode','auto');
writerobj = VideoWriter('sample.avi','Uncompressed AVI');
open(writerobj);
for i=1:t
clf(fig);
plot(...); % some arbitrary plotting
hold on;
plot(...); % some other arbitrary plotting
axis([0 50 0 50]);
figinfo = hardcopy(fig,'-dzbuffer','-r0');
writeVideo(writerobj, im2frame(figinfo));
end
close(writerobj);

You can pass the handle of the desired figure or axis to GETFRAME to ensure that it doesn't capture another window.

I may depend on the renderer you're using. If it's 'painters', then you should be OK, but if it's anything else, such as 'OpenGL', then I think it has to get the frame data from the graphics card, which means that if you have something overlapping the window, then that may end up in the output of getframe.

As someone has already stated you don't have to use getframe, however if you insist on using it you can use
set(fig,'Renderer','zbuffer')
and this should fix your issue.

If you use getframe in many subplots, try to add at the end:
I think the get frame works fine it just the rendering a bit was unpositioned.
clf(fig)
% use 1st frame to get dimensions
[h, w, p] = size(frames(1).cdata);
hf = figure;
% resize figure based on frame's w x h, and place at (150, 150)
set(hf,'Position', [150 150 w h]);
axis off
% Place frames at bottom left
movie(hf,frames,4,30,[0 0 0 0]);
close(gcf)

Related

Freeze the axes size in matlab

I have images captured in many frames. All the frames have different sizes so I set the global maximum and minimum of each axes and used axis command like below:
h = figure;
axis([-8.4188e+03 -7.9061e+03 -102.6261 518.2502 -25.4673 0.2780])
%axis tight manual % this ensures that getframe() returns a consistent size
filename = 'testanim.gif';
But the animation boxes still keep changing the sizes although I have found the maximum and minimum limits of Xs, Ys and Zs. Do I need something more in my code?
This is the code I use for plotting:
% read the data
for k=1:length(FileNames)
FName = plyfiles(k).name;
plys=pcread(['Files\',FName]);
pcshow(plys) % Capture the plot as an image
frame = getframe(h);
im = frame2im(frame);
[imind,cm] = rgb2ind(im,256); % Write to the GIF File
if k == 1
imwrite(imind,cm,filename,'gif', 'Loopcount',inf);
else
imwrite(imind,cm,filename,'gif','WriteMode','append');
end
end
pcshow will, just like imshow or plot, reset the axes it writes to. You can prevent this by setting
hold on
after creating the axes. However, now the point clouds will be shown on top of the previous ones, so you will also have to clear the axes before plotting a new one.
The easiest solution is, instead of holding the plot, to set the axes position every time after plotting. That is, do
set(gca, 'PropertyName', property_value)
after the pcshow call. The properties to set are, I believe, 'XLim', 'YLim', and 'ZLim'.

Animation of figure with subplots using VideoWriter in MATLAB

I'm trying to create an animation file in MATLAB from a figure with 2 subplots using the VideoWriter. However, the avi file that I get includes only one of the subplots.
Here is the code:
clc
clear
vidObj = VideoWriter('randdata');
open(vidObj)
figure (1)
for i = 1:100
clf
subplot(1,2,1)
imagesc(rand(100))
subplot(1,2,2)
imagesc(rand(100))
drawnow
CF = getframe;
writeVideo(vidObj,CF);
end
There must be something simple going wrong here but I don't know what. I would like to capture the entire figure.
The documentation for getframe states in the first line:
F = getframe captures the current axes
So it's capturing the axes, not figure.
You want to use it as also specified in the documentation
F = getframe(fig) captures the figure identified by fig. Specify a figure if you want to capture the entire interior of the figure window, including the axes title, labels, and tick marks. The captured movie frame does not include the figure menu and tool bars.
So your code should be
clc; clear
vidObj = VideoWriter('randdata');
open(vidObj);
figure(1);
for ii = 1:100
clf
subplot(1,2,1)
imagesc(rand(100))
subplot(1,2,2)
imagesc(rand(100))
drawnow;
% The gcf is key. You could have also used 'f = figure' earlier, and getframe(f)
CF = getframe(gcf);
writeVideo(vidObj,CF);
end
For ease, you might want to just get a File Exchange function like the popular (and simple) gif to create an animated gif.

MATLAB's drawnow doesn't flush

Is there any reason that MATLAB's drawnow wouldn't flush?
This is my code:
j=1;
for k = 1:length(P)
for i = 1:n
plot(P(k,j),P(k,j+1),'.');
j = j+2;
end
axis equal
axis([-L L -L L]);
j=1;
drawnow
end
(rungekutta4 is my own function I wrote, and it works OK, so the problem isn't there.)
The particles just stay drawn on the plot and don't get overwritten every time the loop executes.
How could I fix this problem?
The proper and efficient way to do this is with handle graphics. You should also vectorize your plot commands.
% Example data to make runnable
L = 1;
n = 10; % Number of points
P = 2*rand(1e2,n+1)-1;
% Initialize plot, first iteration
h = plot(P(1,1:n),P(1,2:n+1),'.'); % Plot first set of points and return handle
axis equal;
axis([-L L -L L]);
hold on; % Ensure axis properties are fixed
drawnow;
% Animate
for k = 2:size(P,1) % size is safer in this case
% Use handle to update the positions of the previously plotted points
set(h,{'XData','YData'},{P(k,1:n),P(k,2:n+1)});
drawnow;
pause(0.1); % Slow down animation a bit to make visible
end
Calling clf and/or plot on each iteration of an animation causes many things already in memory to be unnecessarily deleted and reallocated, resulting much slower code. It may also result in flickering in some cases.
See also this very similar question and answer.
When you want to animate something, you want to, of course, force draw. Thats what the command drawnow is there for. But there are other things to consider!
One of them is that you need to make sure that everything is drawn in each frame. For that, use the hold on function just before you start drawing (plot).
However, you also need to make sure that you clear the image before drawing, else the plots will stack forever. Use the clf "clear figurecommand before the previously mentionedhold on` and that will do the job.
remember that if the animation is too fast you can always add a pause(0.2) line after drawnow to slow it.

Plot is not reset

i need your help. My program reads a M-File which is a recorded Video.
To display each image i use "imagesc", because the image is saved as a 200x200 Matrix with normalized values ranging from 0 to 1.
After reading each image i do some calculus. The Result should be displayed as an overlay to the image(one Point, and one Line). With the code below this works as expected for the first iteration of the loop.
At all further iterations the image is redrawn(which is correct) but the Point and Line is not cleared.
How can i achieve that the plots are cleared when a new image is displayed.
I tried several variations with the "hold" command. But got no success.
Additional question(not that important):
Is it possible to exchange the "plot" commands below with "set"(especially for the Point)?
My program consist of several more Axes Elements which i cut out to keep the example simple. This means my UI is very slow with "plot" commands so i tried to speed it up with "set".
It works quite well, but I'm not sure if a simple Point can be displayed with "set".
Thanks in advance.
function work()
h_figure = figure('Name','MainFig');
hImage.ax = axes('Units', 'Pixels','Position', [50 375 200 200]);
imagesc('Parent',hImage.ax,'CData',zeros(200));
hImage.axc = get(gca, 'Children');
hProfileLeft.ax = axes('Position', [50 200 200 100]);
hProfileLeft.pl = plot(hProfileLeft.ax, 1:200);
for(frame = obj.Startframe:obj.Endframe)
imgIntens= obj.video.A.intens(:,:,frame);
ProfileResult = doSomeCalc(someArgs);
set(hImage.axc, 'CData', imgIntens); % Show Image(200x200 double)
hold(hImage.ax, 'on'); % Using hold so that plot is overlayed
plot(ProfileResult.peaks.x, ProfileResult.peaks.y,'Parent',hImage.ax); % Simple Point
plot(ProfileResult.corridor.left, 1:200, 'Parent',hImage.ax); % Line
set(hProfileLeft.pl,'YData', ProfileResult.trace); % Draw data to different axes
hold(hImage.ax, 'off');
end
end
I encountered the same annoying behavior. For me the conclusion was to manually call cla.
And use line instead of plot, it has more options (especially nice that you can label the lines yourself) and won't delete the plot when called, also returns you the handles. Once you got the handles you can delete them separately.

Show more than one figure one by one in MATLAB

I have 20 figures to display one after another like slide show. Can I do it using Imshow in Matlab? Any sort of help will be appreciated.
Couple options:
Open a figure for each plot
Open and close a figure for each plot
Reuse one figure
Open a figure for each plot
for i=1:20
h = figure;
%plot here
pause
end
Open and close a figure for each plot
for i=1:20
h = figure;
%plot
pause
close gcf
end
Reuse one figure
h=figure
for i=1:20
clf(h);
%plot
pause
end
OR depending on what you are plotting, you can use the refreshdata method.
If you use #Jonas' method, and if you have dual monitors, you have to force the figure to the main monitor for getframe to actually work, as per. You can do this via:
ff=figure;
movegui(ff)
You can use MOVIE to display plots/images one after the other. For this, you create the figures, capture them via GETFRAME, and then you can call movie. See this example from the help for getframe
Z = peaks; surf(Z)
axis tight
set(gca,'NextPlot','replacechildren');
for j = 1:20
surf(sin(2*pi*j/20)*Z,Z)
F(j) = getframe;
end
movie(F,20) % Play the movie twenty times