I am currently trying to make a video using the writeVideo function in MATLAB. I have made a GUI using GUIDE which includes a slider, a few checkboxs, and a single axes (tagged as axes1). When I move the slider, the axes will plot certain shapes that change according to the slider value.
What I am trying to do is record a video of the GUI being used to show the functionality in a presentation. However, when I play back the video (after making it using writeVideo), it shows the slider value moving and the checkboxes being checked correctly, but the plot never changes (i.e. it will only show the original shape). This seems to be some refresh error, however, anything I have tried has not worked (refresh, drawnow, etc.)
Any idea why this is happening? The following is the code I am trying to implement:
vidObj = VideoWriter('test.avi','Motion JPEG AVI');
open(vidObj);
flag = 0;
if flag<12 %movie will be 12 frames long
flag = flag+1;
if slider<1
plot something...
elseif slider>=1 && slider<2
plot something else...
etc...
elseif slider<=5
plot something else...
end
hFigure = findobj('Name','gui');
currFrame = getframe(hFigure);
writeVideo(vidObj,currFrame);
clear hfigure currFrame image;
else
fprintf('done\n')
close(vidObj);
end
As stated, I can then use implay to play back the test.avi file, however, the plot never updates.
Thanks in advance
Note: I am using MATLAB R2012b
EDIT:
The following is how I ended up creating my video: maybe this will help someone who was facing similar issues to the one stated above.
I basically gave up on using getframe and decided to 1) get screenshots, then 2) turn the screenshots into a movie. To get the screenshots, I first ran my program then, in the command window, invoked the following code using the java toolkit
i = 1;
while true
robo = java.awt.Robot;
t = java.awt.Toolkit.getDefaultToolkit();
%# Set screen size
rectangle = java.awt.Rectangle(0,0,1000,640);
%# Get the capture
image = robo.createScreenCapture(rectangle);
%# Save it to file
filehandle = java.io.File(sprintf('capture%d.jpg', i));
javax.imageio.ImageIO.write(image,'jpg',filehandle);
pause(.4) %# Wait for 0.4 seconds
i = i + 1;
end
This then continually ran in the background and took snap shots of the screen and stored them into the current directory. to stop it from running, just use Ctrl C. Once I had the screen shots, I used the following code to create the movie:
vidObj = VideoWriter('test.avi','Motion JPEG AVI');
open(vidObj);
for i=7:87 %these are the frames I wanted in my movie
x = num2str(i);
im = horzcat('capture',x);
im1 = horzcat(im,'.jpg')
imdata = imread(im1);
writeVideo(vidObj,imdata);
end
close(vidObj);
getframe is sometimes problematic. I'm not sure I can give an answer, and I can't simply comment because of my reputation, but this link might be of help. After you get the figure from the GUI, turn it into an image and then into a frame. Worth a shot.
If you change your monitor settings to 16 bit color it will solve the problem you are having. This has been documented on the link provided. My previous answer was deleted because I only supplied the link and told you how to solve the problem (sorry) but if you actually click on the link and see what they say or change your monitor settings to 16 bit color everything will work. From the link you can see that people have had this problem since 2009 but it was updated in april 2013 so it is still a problem and changing your monitor settings to 16 bit color is still a solution.
Hope this helps!
http://www.mathworks.com/matlabcentral/newsreader/view_thread/257389
Related
I have a video written with the Xvid MPEG4-Codec. Unfortunately, each frame has an annoying bar to the right and to the bottom of a couple of pixels. What I would like to do is to remove this bar, preferably using MATLAB.
For this purpose, I have written this code to try this out:
function [] = changeVideo(in_path, out_path, reqSize)
videoList = dir(strcat(in_path, '\*.avi'));
for ii = 1:numel(videoList)
vidReader = VideoReader(strcat([in_path '\'], videoList(ii).name));
vidWriter = VideoWriter(strcat([out_path '\'], videoList(ii).name),'MPEG-4');
open(vidWriter);
while hasFrame(vidReader)
% here I would change the size of the frame
writeVideo(vidWriter,readFrame(vidReader));
end
close(vidWriter);
close(vidReader);
end
end
Unfortunately, this does not seem to work. The resulting video has a different memory footprint and quality than the original video. Since MATLAB can read the original video, I was hoping that there is a way to replicate this video, but only change each frame slightly in its size. Is this possible?
Thank you!
I read the blog post on assigning transparency to plot markers. I tried the code on a simple example and all was well. Then I tried a tight loop, plotting a single point at a time (doing this to assign a different color to each point in the graph), and invariably within a few loop cycles, when I grab the "plothandle.MarkerHandle", it's empty. In these cases, the class of this empty object is Matlab.graphics.GraphicsPlaceholder
while when the operation is successful, the class is:
matlab.graphics.primitive.world.Marker
The basic loop follows. colormatrix assigns a [r,g,b] color to each data point.
hold on
opacity = 0.5;
for jk = 1:numel(idx
tmph = plot(foox(jk),fooy(jk),'o','color',colormatrix(jk,:) );
tmpk = tmph.MarkerHandle;
tmpk.FaceColorData = uint8(double(tmpk.EdgeColorData).* [1,1,1,opacity]');
tmpk.EdgeColorData = uint8(double(tmpk.EdgeColorData).* [1,1,1,opacity]');
end
I've tried things like clearing variables every loop, putting in a delay timer, and so on, with no luck. I'm using Matlab R2015a.
EDIT: here's a simple example. What I seem to be finding is that if I run the entire script, it always fails. If I break it into two pieces where noted and execute the second section with a separate key stroke (ctrl-enter or selectall/F9 in the IDE editor), everything works. And yes, I'm aware that "undocumented features" are risky , but since MathWorks still hasn't figured out that allowing transparency -- and indexed color assignments -- are good things for the plot function, I'm still looking for a better workaround than using patch to draw each data point.
figure
xfoo = 1:10;
yfoo = 2*xfoo;
tmph = plot(xfoo,yfoo,'p','color',[1,0,1]);
hold on
opacity = 0.7;
% wait a while here.
tmpk = tmph.MarkerHandle;
tmpk.FaceColorData = uint8(double(tmpk.EdgeColorData).*[1,1,1,opacity]');
tmpk.EdgeColorData = uint8(double(tmpk.EdgeColorData).*[1,1,1,opacity]');
The fact that the script seems to work if you wait a bit between the plot and the retrieval of tmph.MarkerHandle suggests that you have the same issue that was reported on the blog by a user running R2014b. Yair suggested to call drawnow after the plot:
figure
xfoo = 1:10;
yfoo = 2*xfoo;
tmph = plot(xfoo,yfoo,'p','color',[1,0,1]);
hold on
opacity = 0.7;
drawnow;
tmpk = tmph.MarkerHandle;
tmpk.FaceColorData = uint8(double(tmpk.EdgeColorData).*[1,1,1,opacity]');
tmpk.EdgeColorData = uint8(double(tmpk.EdgeColorData).*[1,1,1,opacity]');
The workaround didn't work for a user running R2015a, which doesn't sound promising, but the fact that waiting seems to help for you, is encouraging.
I tries to create a text image (i think it is called that way) in matlab. That means that I want to create an image containing text. The problem is that there is no matlab function that can do this. The solution is that I use text and then captures the output in the figure.
In the beginning I used getframe to capture the output. This went completely fine as long as I did not do anything else on the screen at the same time. The problem is that |getframe| captures whatever is on the screen at the moment, which have led to annoying bugs. In hope of solving this problem I plan to use |print| instead. However, now I have the problem of image resolution changes when print is used. Do anyone know a solution for this?
This is what I have tried so far:
xlen = 1200; ylen = 700;
im = uint8(255*ones(ylen,xlen,3));
hf = figure('color','white','units','normalized','position',[.1 .1 .8 .8]);
image(ones(size(im)));
set(gca,'units','pixels','position',[5 5 size(im,2)-1 size(im,1)-1],'visible','off')
text('units','pixels','position',[1 ylen/2],'fontsize',60,'FontWeight','Bold','string','This is text')
set(hf,'Units','pixels')
set(hf,'Position',[100,100,xlen,ylen],'paperpositionmode','auto');
print(hf, '-dpng', 'myText.png');
Saving images in matlab can be a real struggle.
I found my solution by using export_fig from the mathlab file exchange (see
http://www.mathworks.com/matlabcentral/fileexchange/23629-export-fig).
Some of the aims of export fig are:
Figure/axes reproduced as it appears on screen
Cropped borders (optional)
Embedded fonts (pdf only)
Ok I have finally found a solution. Matlab uses 150 dpi resolution by default. This is kind of weird since windows use 96 dpi resolution in their operating system and mac uses 72 dpi. However, what I have heard it is recommended to use at least 150 dpi on printed material to get good quality. Anyway, since windows uses 96 dpi, it is clear that you need to set the image resolution to 96 dpi as well to print (refering to matlabs function print) a figure with the right size.
xlen = 1200; ylen = 700;
im = uint8(255*ones(ylen,xlen,3));
hf = figure('color','white','units','normalized','position',[.1 .1 .8 .8]);
image(ones(size(im)));
set(gca,'units','pixels','position',[5 5 size(im,2)-1 size(im,1)-1],'visible','off')
text('units','pixels','position',[1 ylen/2],'fontsize',60,'FontWeight','Bold','string','This is text')
set(hf,'Units','pixels')
set(hf,'Position',[100,100,xlen,ylen],'paperpositionmode','auto');
print(hf, '-dpng', '-r96','myText.png'); % SET RESOLUTION TO '-r96' for windows.
I'm making a GUI in MatLab that asks the user to upload a video file.
Next I want to play it in axes with a fixed window size . However, if the uploaded file is large, Matlab will expand the axes and take over most of my GUI. Is there a way to shrink the image to make it fit the axes?
Does anyone know how to solve this?
Usually Matlab axes are not supposed to change their position if the image is too big.
I can think of two possible problems:
The axes were large from the beginning, but showed small image with margins if the image is small enough
The command of showing the image that you are using is custom and it changes the axes size.
This question is old, but I stumbled across this (looking for something else) so perhaps it will help someone to see what I did.
I wanted to resize pretty large images (1024x 100k-200k pixels) so that my GUI can quickly demonstrate various color operations on a view of these large data sets. I just manually sub-sampled my data as follows (functions below).
Note that this example is an image. To spatially sub-sample a video, I have looped through the video and done something similar in the past on each frame.
[plotWidthPixels, plotHeightPixels] = getPlotAreaPixels(handles.figure1, handles.axes1);
[nSamplesPerLine nLines] = size(iqData);
colInds = decimateToNumber(nLines,plotWidthPixels);
rowInds = decimateToNumber(nSamplesPerLine,plotHeightPixels);
iqDataToPlot = iqData(rowInds,colInds);
First, I got the axis size in pixels:
function [plotWidthPixels, plotHeightPixels] = getPlotAreaPixels(figHandle, axisHandle)
set(figHandle,'Units','pixels')
figSizePix = get(figHandle,'Position');
set(axisHandle,'Units','normalized')
axSizeNorm = get(axisHandle,'Position');
axisSizePix = figSizePix.*axSizeNorm;
plotWidthPixels = ceil(axisSizePix(3)-axisSizePix(1));
plotHeightPixels = ceil(axisSizePix(4)-axisSizePix(2));
Then I used that to decimate the width and height of my image by getting sub-sets of indices that are (crudely approximately) evenly spaced:
function inds = decimateToNumber(lengthOfInitialVector, desiredVectorLength, initialIndex)
if nargin < 3
initialIndex = 1;
end
if (lengthOfInitialVector-initialIndex+1) > desiredVectorLength*2
inds = round(linspace(initialIndex,lengthOfInitialVector,desiredVectorLength));
else
inds = initialIndex:lengthOfInitialVector;
end
I currently have a code in Matlab that takes images from two webcams, overlays them and displays them in a figure which get's updated in time intervals to give semi-realtime.
However, I need to make this realtime, does anyone have any idea of how to overlay two webcam streams like you would do with a 3D movie?
Thanks!
If you mean Anaglyph 3D, having both images you can do the following:
left = imread('vipstereo_hallwayLeft.png');
right = imread('vipstereo_hallwayRight.png');
imshow(cat(3, left(:,:,1), right(:,:,2:3)));
both png's already come with the image processing toolbox.
The result will be this (and you can look at it with Red/Cyan glasses. I did!):
I already tried this method with real pictures in 2 ways:
1. 2 pictures taken at the same time with 2 diferent cameras a little displaced;
2. 2 pictures taken in a very short time with a moving camera. (burst mode)
And they both gave excelent results.
Then, to do it with 2 webcams, you need to:
1. init them properly;
2. set them to get 1 frame per trigger;
3. trigger them and get both frames;
4. mix frames and show them.
I do not have 2 webcams so I was no able to test it, but I think this code can do it:
Cameras setup:
% Get a handle to each cam
Lvid = videoinput('winvideo', 1, 'YUY2_1280x1024');
Rvid = videoinput('winvideo', 2, 'YUY2_1280x1024');
% Set them to get one frame/trigger
Lvid.FramesPerTrigger = 1;
Rvid.FramesPerTrigger = 1;
Then do an infinite loop to get frames, mix them and show the result.
while(1)
% Trigers both video sources
start(Lvid);
start(Rvid);
% Get the frames
left = getdata(Lvid);
right = getdata(Rvid);
% Convert them to RGB
left = ycbcr2rgb(left);
right = ycbcr2rgb(right);
% mix them (R from right + GB from left)
frame = cat(3, left(:,:,1), right(:,:,2:3));
% show
imshow(frame);
pause(0.0001) % to refresh imshow
end
Note that since my webcam is YUV i have to convert it to RGB prior to mixing the images.
Hope this helps you!
I'd suggest doing it in OpenCV.