Error using VideoWriter - matlab

I am creating an avi file from a bunch of frames using VideoWriter in MATLAB. But I'm getting this error:
??? Error using ==> VideoWriter.VideoWriter>VideoWriter.writeVideo at 339
The 'cdata' field of FRAME must not be empty
Since I can create jpg files from the same script, I know an image pops up.
Here's my code:
%% Graph one site at a time
writerObj = VideoWriter(['US_O3_MDA8_EUS_' num2str(years(y)) '_10-90.avi']);
writerObj.FrameRate = 1;
open(writerObj);
% Map of conterminous US
nFrames = length(date); % Number of frames.
for k = 1:nFrames % Number of days
ax = figure(1);
ax = usamap({'TX','ME'});
latlim = getm(ax, 'MapLatLimit');
lonlim = getm(ax, 'MapLonLimit');
states = shaperead('usastatehi',...
'UseGeoCoords', true, 'BoundingBox', [lonlim', latlim']);
geoshow(ax, states, 'FaceColor', 'none')
% framem off; gridm off; mlabel off; plabel off
hold on
% Plot data
h = scatterm(ax,str2double(Lat_O3{k}), str2double(Lon_O3{k}), 40, str2double(data_O3{k})*1000, 'filled');
% Set colorbar and title info
% Capture the frame
frame = getframe;
writeVideo(writerObj,frame);
clf
end
% Save as AVI file
close(writerObj);
close(gcf)

Related

Real time NI-DAQ data plot in Matlab

I'm trying to get a real time plot of data I'm acquiring with a NI USB-6008. I tried doing the same with arduino and got a plot exactly as I wanted (see here https://i.stack.imgur.com/08kzU.jpg), and the x-axis would move in real-time, but I couldn't define the sampling rate. With NI I was able to define the sampling rate I wanted but I can't display the data in a continuous, real-time plot, I can only see 1 sec at a time and I need to be able to have access to all the data acquired since I want to measure a real-time EEG. I'm a new matlab user, so please consider no previous knowledge.
This is the code I've got so far:
clear
close all
dq = daq("ni");
ch1 = addinput(dq, "Dev1", "ai0", "Voltage");
dq.Rate = 1000;
dq.ScansAvailableFcn = #(src,evt) plotDataAvailable(src, evt);
dq.ScansAvailableFcnCount = 100;
start(dq, "Duration", seconds(5))
while dq.Running
pause(0.5);
end
time = 0;
data = 0;
n = ceil(dq.Rate/10);
%Set up Plot
figure(1)
plotGraph = plot(time,data);
title('DAQ data log','FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10); ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
h = animatedline;
function plotDataAvailable(src, ~)
while ishandle(plotGraph) % Loop when Plot is Active will run until plot is closed
data = read(dq,n);
t = datetime('now');
% Add points to animation
addpoints(h,datenum(t),data)
% Update axes
ax.XLim = datenum([t-seconds(15) t]);
datetick('x','keeplimits')
drawnow
end
end
This was my previous arduino code that showed me the plot I needed (with the wrong sampling rate):
clear
clc
%User Defined Properties
a = arduino('com4','uno'); % Define the Arduino Communication port
plotTitle = 'Arduino Data Log'; % Plot title
%Define Function Variables
time = 0;
data = 0;
%Set up Plot
figure(1)
plotGraph = plot(time,data,'-r' );
title(plotTitle,'FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10); ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
ax.YLim = [0 5]; % Sets y-min and y-max
while ishandle(plotGraph) % Loop when Plot is Active will run until plot is closed
startIteration = tic;
voltagem = readVoltage(a,'A0')
t = datetime('now');
% Add points to animation
addpoints(h,datenum(t),voltagem)
% Update axes
ax.XLim = datenum([t-seconds(15) t]);
datetick('x','keeplimits')
drawnow
end
I've tried using this while loop on my NI data but it doesn't work.
I would really appreciate your help.
You've got the order of the operations wrong. What your code is doing at the moment is:
initialize the data acquisition
read the data from the hardware while trying to add data to lines that don't exist
initialize the animated lines.
Furthermore, in your addpoints call you're trying to plot t, which is a scalar, and data, which is an array.
What you should do instead is:
clear
close all
% Set up the plot
figure(1)
title('DAQ data log','FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10)
ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
% Set up the data acquisition
dq = daq("ni");
ch1 = addinput(dq, "Dev1", "ai0", "Voltage");
dq.Rate = 1000;
dq.ScansAvailableFcn = {#plotDataAvailable, h, ax}; % pass also the handle to the line and to the axes
dq.ScansAvailableFcnCount = 100;
% Now you start the data acquisition
start(dq, "Duration", seconds(5))
function plotDataAvailable(src, evt, h, ax)
data = read(dq, n);
% maybe your time array should look something like this?
t = datetime(now) - seconds((length(data)-1:-1:0)./src.Rate);
% Add points to animated line
addpoints(h, datenum(t), data)
% Update axes
% ax.XLim = datenum([t-seconds(15) t]); % this line is useless, why would you have a 15s window when your data acquisition is only 5s long?
datetick('x','keeplimits')
drawnow
end
I can't try this at the moment, so it might not work exactly.
So I think I finally got it, because I got the plot like I wanted, with the x-axis moving with real-time. However I still get an error saying "Unrecognized table variable name 'Dev1_ai0'" event tho I checked that's the name of the row that I want. Anyways, this is what my code looks now.
clear
close all
time = 0;
data = 0;
% Set up the plot
figure(1)
plotGraph = plot(time,data,'-r' );
title('DAQ data log','FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10)
ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
% Set up the data acquisition
dq = daq("ni");
ch1 = addinput(dq, "Dev1", "ai0", "Voltage");
dq.Rate = 1000;
% Start the data acquisition
start(dq, "Duration", seconds(10))
n = ceil(dq.Rate/10);
while ishandle(plotGraph)
data = read(dq, n);
voltage = data.Dev1_ai0;
t = datetime('now');
for i = 1:100
% Add points to animated line
if isvalid(h)
addpoints(h, datenum(t), voltage(i))
end
end
% Update axes
ax.XLim = datenum([t-seconds(15) t]);
datetick('x','keeplimits')
drawnow
end
disp('Plot Closed')

Playing .avi in linux

I have written a code to save two movies in Matlab. The problem is that, the movie "graphh.avi" is consist of first movie("chert") also. I want it to show just graphs and not the first saved movie("chert.avi").
Could anyone help? Any answer is highly appreciated.
clear all
close all
cla
h = plot(x, y, '.g', 'MarkerSize', 10);
set(gca,'Color',[0 0 0]);
set(gcf,'doublebuffer','on')
set(gca,'YTick',[]);
set(gca,'XTick',[]);
plot(x,y,'.g','markersize',10)
drawnow
currFrame = getframe;
writeVideo(vidObj,currFrame);
h = plot(x, y, '.g', 'MarkerSize', 10);
drawnow
hist(blocksize)
currFrame = getframe;
writeVideo(vid,currFrame);
end
close(vidObj);
close(vid)
The code after doing the first answer becomes as below. The problem solved but there is another problem now: black movie with green points became so messy.
clear all
close all
l = 20;
r = 3;
v = 0.5;
dt = 1;
nn=200;
figure(h1); % set figure 1 as current figure
h = plot(x, y, '.g', 'MarkerSize', 10);
set(gca,'Color',[0 0 0]);
set(gcf,'doublebuffer','on')
set(gca,'YTick',[]);
set(gca,'XTick',[]);
plot(x,y,'.g','markersize',10)
drawnow
currFrame = getframe(h1); % gets only figure 1
writeVideo(vidObj,currFrame);
h = plot(x, y, '.g', 'MarkerSize', 10);
drawnow
figure(h2); % set figure 2 as current figure
hist(blocksize)
currFrame = getframe(h2); % gets only figure 2
writeVideo(vid,currFrame);
end
close(vidObj);
close(vid);
Use figures handles when calling getframe. See how I modified your code:
% some code...
vvy = v.*sin(tetha);
h1 = figure('Color',[0 0 0])
axis([0 l 0 l])
% some more code...
h2 = figure
hold on
vid = VideoWriter('graphh.avi');
% and more code...
% for loop
figure(h1); % set figure 1 as current figure
% plot whatever on this figure
currFrame = getframe(h1); % gets only figure 1
writeVideo(vidObj,currFrame);
% blah blah...
figure(h2); % set figure 2 as current figure
% plot whatever on this figure
currFrame = getframe(h2); % gets only figure 2
writeVideo(vid,currFrame);
% end of loop
EDIT:
in your modified code you're calling h = plot(x, y, '.g', 'MarkerSize', 10); three times in a row for no reason, so get rid of it. the problem you encountered stems from plotting another set of point in addition to the previous one, so the axes get filled with points. One solution for that is to use set(h,'XData',x,'YData',y) like so:
figure(h1); % set figure 1 as current figure
set(gca,'Color',[0 0 0]);
set(gcf,'doublebuffer','on')
set(gca,'YTick',[]);
set(gca,'XTick',[]);
if exist('h','var') && ishandle(h) % if handle exists just change coordinates
set(h,'XData',x,'YData',y)
else % only for the first time you plot that
h = plot(x, y, '.g', 'MarkerSize', 10);
end
drawnow
currFrame = getframe(h1); % gets only figure 1
writeVideo(vidObj,currFrame);

Capture image of a detected face using webcam?

I am new to MATLAB. I need to capture image and save it into a folder. THis is my matlab code for detect face.
% Create the face detector object.
faceDetector = vision.CascadeObjectDetector();
% Create the point tracker object.
pointTracker = vision.PointTracker('MaxBidirectionalError', 2);
% Create the webcam object.
cam = webcam();
% Capture one frame to get its size.
videoFrame = snapshot(cam);
frameSize = size(videoFrame);
% Create the video player object.
videoPlayer = vision.VideoPlayer('Position', [100 100 [frameSize(2), frameSize(1)]+30]);
runLoop = true;
numPts = 0;
frameCount = 0;
%%x = 0;
while runLoop && frameCount < 400
%% while(x<1)
% Get the next frame.
videoFrame = snapshot(cam);
videoFrameGray = rgb2gray(videoFrame);
frameCount = frameCount + 1;
if numPts < 10
% Detection mode.
bbox = faceDetector.step(videoFrameGray);
if ~isempty(bbox)
% Find corner points inside the detected region.
points = detectMinEigenFeatures(videoFrameGray, 'ROI', bbox(1, :));
% Re-initialize the point tracker.
xyPoints = points.Location;
numPts = size(xyPoints,1);
release(pointTracker);
initialize(pointTracker, xyPoints, videoFrameGray);
% Save a copy of the points.
oldPoints = xyPoints;
% the orientation of the face.
bboxPoints = bbox2points(bbox(1, :));
% Convert the box corners into the [x1 y1 x2 y2 x3 y3 x4 y4]
% format required by insertShape.
bboxPolygon = reshape(bboxPoints', 1, []);
% Display a bounding box around the detected face.
videoFrame = insertShape(videoFrame, 'Polygon', bboxPolygon, 'LineWidth', 3);
% Display detected corners.
videoFrame = insertMarker(videoFrame, xyPoints, '+', 'Color', 'white');
end
else
% Tracking mode.
[xyPoints, isFound] = step(pointTracker, videoFrameGray);
visiblePoints = xyPoints(isFound, :);
oldInliers = oldPoints(isFound, :);
numPts = size(visiblePoints, 1);
if numPts >= 10
% Estimate the geometric transformation between the old points
% and the new points.
[xform, oldInliers, visiblePoints] = estimateGeometricTransform(...
oldInliers, visiblePoints, 'similarity', 'MaxDistance', 4);
% Apply the transformation to the bounding box.
bboxPoints = transformPointsForward(xform, bboxPoints);
% Convert the box corners into the [x1 y1 x2 y2 x3 y3 x4 y4]
% format required by insertShape.
bboxPolygon = reshape(bboxPoints', 1, []);
% Display a bounding box around the face being tracked.
videoFrame = insertShape(videoFrame, 'Polygon', bboxPolygon, 'LineWidth', 3);
% Display tracked points.
videoFrame = insertMarker(videoFrame, visiblePoints, '+', 'Color', 'white');
% Reset the points.
oldPoints = visiblePoints;
setPoints(pointTracker, oldPoints);
end
end
% Display the annotated video frame using the video player object.
step(videoPlayer, videoFrame);
% Check whether the video player window has been closed.
runLoop = isOpen(videoPlayer);
end
% Clean up.
clear cam;
release(videoPlayer);
release(pointTracker);
release(faceDetector);
Please help me to capture image and save.
I tried this code for capture image and save
vid = videoinput('dcam',1,'RGB24_640x480');
preview(vid);
start(vid);
im=getdata(vid);
figure,imshow(im);
write(im,'test1image.jpg');
When I try this code it gives and error,
Error using videoinput (line 233)
There are no devices installed for the specified ADAPTORNAME. See IMAQHWINFO.
Error in takeimage (line 1)
vid = videoinput('dcam',1,'RGB24_640x480');
You may need to download a support package for the Image Acquisition Toolbox for your particular camera. If you are using a regular USB webcam, then you probably need the "OS Generic Video Interface" support package.

To refresh imshow in Matlab?

I want to convert this answer's code to imshow.
It creates a movie in MOVIE2AVI by
%# preallocate
nFrames = 20;
mov(1:nFrames) = struct('cdata',[], 'colormap',[]);
%# create movie
for k=1:nFrames
surf(sin(2*pi*k/20)*Z, Z)
mov(k) = getframe(gca);
end
close(gcf)
movie2avi(mov, 'myPeaks1.avi', 'compression','None', 'fps',10);
My pseudocode
%# preallocate
nFrames = 20;
mov(1:nFrames) = struct('cdata',[], 'colormap',[]);
%# create movie
for k=1:nFrames
imshow(signal(:,k,:),[1 1 1]) % or simply imshow(signal(:,k,:))
drawnow
mov(k) = getframe(gca);
end
close(gcf)
movie2avi(mov, 'myPeaks1.avi', 'compression','None', 'fps',10);
However, this creates the animation in the screen, but it saves only a AVI -file which size is 0 kB. The file myPeaks1.avi is stored properly after running the surf command but not from imshow.
I am not sure about the command drawnow.
Actual case code
%% HSV 3rd version
% https://stackoverflow.com/a/29801499/54964
rgbImage = imread('http://i.stack.imgur.com/cFOSp.png');
% Extract blue using HSV
hsvImage=rgb2hsv(rgbImage);
I=rgbImage;
R=I(:,:,1);
G=I(:,:,2);
B=I(:,:,3);
R((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
G((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
B((hsvImage(:,:,1)>(280/360))|(hsvImage(:,:,1)<(200/360)))=255;
I2= cat(3, R, G, B);
% Binarize image, getting all the pixels that are "blue"
bw=im2bw(rgb2gray(I2),0.9999);
% The label most repeated will be the signal.
% So we find it and separate the background from the signal using label.
% Label each "blob"
lbl=bwlabel(~bw);
% Find the blob with the highes amount of data. That will be your signal.
r=histc(lbl(:),1:max(lbl(:)));
[~,idxmax]=max(r);
% Profit!
signal=rgbImage;
signal(repmat((lbl~=idxmax),[1 1 3]))=255;
background=rgbImage;
background(repmat((lbl==idxmax),[1 1 3]))=255;
%% Error Testing
comp_image = rgb2gray(abs(double(rgbImage) - double(signal)));
if ( sum(sum(comp_image(32:438, 96:517))) > 0 )
break;
end
%% Video
% 5001 units so 13.90 (= 4.45 + 9.45) seconds.
% In RGB, original size 480x592.
% Resize to 480x491
signal = signal(:, 42:532, :);
% Show 7 seconds (298 units) at a time.
% imshow(signal(:, 1:298, :));
%% Video VideoWriter
% movie2avi deprecated in Matlab
% https://stackoverflow.com/a/11054155/54964
% https://stackoverflow.com/a/29952648/54964
%# figure
hFig = figure('Menubar','none', 'Color','white');
Z = peaks;
h = imshow(Z, [], 'InitialMagnification',1000, 'Border','tight');
colormap parula; axis tight manual off;
set(gca, 'nextplot','replacechildren', 'Visible','off');
% set(gcf,'Renderer','zbuffer'); % on some Windows
%# preallocate
N = 40; % 491;
vidObj = VideoWriter('myPeaks3.avi');
vidObj.Quality = 100;
vidObj.FrameRate = 10;
open(vidObj);
%# create movie
for k=1:N
set(h, 'CData', signal(:,k:k+40,:))
% drawnow
writeVideo(vidObj, getframe(gca));
end
%# save as AVI file
close(vidObj);
How can you substitute the drawing function by imshow or corresponding?
How can you store the animation correctly?
Here is some code to try:
%// plot
hFig = figure('Menubar','none', 'Color','white');
Z = peaks;
%h = surf(Z);
h = imshow(Z, [], 'InitialMagnification',1000, 'Border','tight');
colormap jet
axis tight manual off
%// preallocate movie structure
N = 40;
mov = struct('cdata',cell(1,N), 'colormap',cell(1,N));
%// aninmation
for k=1:N
%set(h, 'ZData',sin(2*pi*k/N)*Z)
set(h, 'CData',sin(2*pi*k/N)*Z)
drawnow
mov(k) = getframe(hFig);
end
close(hFig)
%// save AVI movie, and open video file
movie2avi(mov, 'file.avi', 'Compression','none', 'Fps',10);
winopen('file.avi')
Result (not really the video, just a GIF animation):
Depending on the codecs installed on your machine, you can apply video compression, e.g:
movie2avi(mov, 'file.avi', 'Compression','XVID', 'Quality',100, 'Fps',10);
(assuming you have the Xvid encoder installed).
EDIT:
Here is my implementation of the code you posted:
%%// extract blue ECG signal
%// retrieve picture: http://stackoverflow.com/q/29800089
imgRGB = imread('http://i.stack.imgur.com/cFOSp.png');
%// detect axis lines and labels
imgHSV = rgb2hsv(imgRGB);
BW = (imgHSV(:,:,3) < 1);
BW = imclose(imclose(BW, strel('line',40,0)), strel('line',10,90));
%// clear those masked pixels by setting them to background white color
imgRGB2 = imgRGB;
imgRGB2(repmat(BW,[1 1 3])) = 255;
%%// create sliding-window video
len = 40;
signal = imgRGB2(:,42:532,:);
figure('Menubar','none', 'NumberTitle','off', 'Color','k')
hImg = imshow(signal(:,1:1+len,:), ...
'InitialMagnification',100, 'Border','tight');
vid = VideoWriter('signal.avi');
vid.Quality = 100;
vid.FrameRate = 60;
open(vid);
N = size(signal,2);
for k=1:N-len
set(hImg, 'CData',signal(:,k:k+len,:))
writeVideo(vid, getframe());
end
close(vid);
The result look like this:

MATLAB Figure Visible Off

I'm trying to save .jpg files from MATLAB, but I don't want to have the figure pop up every time since this really slows down the process. However, setting 'visible' to 'off' doesn't seem to work. What can I do to get the Figure window to not pop up?
nFrames = 2557; % Number of frames. Number of days between 1/1/2008 and 1/31/2014
for k = 183:nFrames % 183 (7/1/2008) to the number of days. Data before this is either missing or from HI
% Map of conterminous US
ax = figure(1);
set(ax, 'visible', 'off', 'units','normalized','outerposition',[0 0 1 1]) % Make window that shows up full sized, which makes saved figure clearer
ax = usamap('conus');
states = shaperead('usastatelo', 'UseGeoCoords', true,...
'Selector',...
{#(name) ~any(strcmp(name,{'Alaska','Hawaii'})), 'Name'});
faceColors = makesymbolspec('Polygon',...
{'INDEX', [1 numel(states)], 'FaceColor', 'none'}); % NOTE - colors are random
geoshow(ax, states, 'DisplayType', 'polygon', ...
'SymbolSpec', faceColors)
framem off; gridm off; mlabel off; plabel off
hold on
% Plot data
scatterm(ax,str2double(Lat_PM25{k}), str2double(Lon_PM25{k}), 40, str2double(data_PM25{k}), 'filled'); % Plot a dot at each Lat and Lon with black outline around each dot (helps show dots that are too low for it to be colored by the color bar
% Draw outline around dot with 'MarkerEdgeColor', [0.5 0.5 0.5] for gray
hold on
% Colorbar
caxis([5 30]);
h = colorbar;
ylabel(h,'ug/m3');
% Title
% date = datenum(2007, 04, 29) + k; % Convert t into serial numbers.
title(['PM2.5 24-hr Block Average Concentration ', datestr(cell2mat(date_PM25(k)), 'mmm dd yyyy')]); % Title changes every day;
% Capture the frame
mov(k) = getframe(gcf);
% Set size of paper
set(gcf,'Units','points')
set(gcf,'PaperUnits','points')
size = get(gcf,'Position');
size = size(3:4);
set(gcf,'PaperSize',size)
set(gcf,'PaperPosition',[0,0,size(1),size(2)])
% Save as jpg (just specify other format as necessary) - Must set 'facecolor' to 'none' or else color of states turn out black
eval(['print -djpeg map_US_' datestr(cell2mat(date_PM25(k)),'yyyy_mm_dd') '_PM25_24hrBlkAvg.jpg']);
clf
end
The problem is with getframe. A detailed answer was given in this thread and in this discussion.
In short you need to avoid getframe and instead do something like the following:
ax = figure(1);
set(ax, 'visible', 'off')
set(ax, 'PaperPositionMode','auto')
aviobj = avifile('file.avi');
....
for k=1:N
%# all the plotting you did before the getframe
img = hardcopy(ax, '-dzbuffer', '-r0');
aviobj = addframe(aviobj, im2frame(img));
end
aviobj = close(aviobj);