Code covered by the BSD License  

Highlights from
Tools for generating and playing video realtime

image thumbnail

Tools for generating and playing video realtime

by

 

22 Mar 2012 (Updated )

Generation of video in matlab, with the means of playing it realtime in a separte thread via VLC

generateMotionStimulus(type, UniformMotion, outputFileName)
function generateMotionStimulus(type, UniformMotion, outputFileName)

% generates example video files for perceptual studies. These are saved in
% the current folder as default 'Stimulus.avi'.
% 
% type is one out of:
%      'aliasedDisk'   - displays test image with common error in
%                        perceptual studies: ALIASING
%      'fuzzyDisk'     - displays same disk as above, but with a method of
%                        proper anti-aliasing it (NOT the same as smoothing)
%      'threePatterns' - common perceptual stimulus kind, Gabor
%                        pattern-like
%      'stefanArt'     - pretty moving pattern based on log spirals

% see licence.txt for licence details. Copyright 2012 Stefan Karlsson

if nargin <3
    outputFileName = 'Stimulus.avi';end
if nargin <2 
    UniformMotion = 1; end
if nargin <1
    type = 'stefanArt'; end

global hfig bKillAll spdRot rotAn DispFramerate;

bKillAll = 0; %bKillAll will be used to flag when the user shuts down the main figure

%%%%%%%%%%%%%% General Configurable Params %%%%%%%%%%%%%%
DispFramerate = 30; %frames/second
vidObj = VideoWriter(outputFileName);
vidObj.Quality =100;
vidObj.FrameRate =DispFramerate;
open(vidObj);

%%%%%%%%%%% image generation Params %%%%%%%%%%%
spdMotion = 0.55;   %speed of motion of the patterns generated
cen1      = 0.55;   %centre of circle 1(x offset)
cW        = 0.9;   %radius of big circles
cW2        = 0.3;   %radius of small circles
cFuz      = 2;      %fuzziness of the boundary
rotAn     = 0;      %angle of rotation
spdRotMax    = -pi/80;      %speed of rotation, when activated 
spdRot = 0;
spdRot2 = 0;
cDetail   = 0.7;
L = 5;
thet = pi/8;
imSize = 250; 

%%%%%%% constants, DO NOT CHANGE  %%%%%%%%%
DispFrameInterval = 1/DispFramerate; %secs per frame
spd =spdMotion/DispFramerate; %pattern translation will depend on frame rate

%%%%%%%%%%%%%%%% Data structures pre-allocation %%%%%%%%%%%%
IMS  = zeros(imSize);

%variables for x-y coordinates. For generating testims
[iix,iiy] = meshgrid(linspace(-1,1,imSize));
% create, and get handles for the graphics objects to use. Here only an image 
% object embedded in a figure:
hImObj =  setupGraphics(imSize);
hax = gca;
lag = 0; %to measure that computer can handle the animation, lag should always be below tolerance;
jj = 0; %counter variables init
xOffset = 0;
yOffset = 0;

%%%%%%%%%%% main loop %%%%%%%%%%%
while ~bKillAll  %the global variable bKillAll will be set when the user kills the figure (see callbacks at bottom of this file)
    jj=jj+1;
    tStartOfFrame = tic; % timing
    %%%%%%%%%%%Test-image generation %%%%%%%%%%%%%
    rotAn = rotAn + spdRot2;
%%%%%% uniform motion of the entire pattern:
if UniformMotion == 1
     xOffset =      0.2*sin(pi*(jj+0.5)*spd*3);
     yOffset = 0.25+0.5*cos(pi*(jj+0.5)*spd  );
elseif UniformMotion == 2
    xOffset =      0.5*sin(pi*(jj+0.5)*spd);
    yOffset =      0.5*cos(pi*(jj+0.5)*spd);
end

iX = (iix- xOffset)*cos(rotAn) - (iiy-yOffset)*sin(rotAn);
iY = (iix- xOffset)*sin(rotAn) + (iiy-yOffset)*cos(rotAn);

if strcmp(type,'stefanArt')
    thet  = pi/4-(pi/2-(spdRot*pi)+0.01);
    thet2 = -pi/4-(pi/2-(spdRot*pi)+0.01);
    IMS =  256*(1+cos((L/abs(sin(thet)))*(cos(thet)*log(sqrt(iX.^2+iY.^2)) + sin(thet)*atan2(iY,iX))))/2; %the log-spiral
    IMS =  IMS + 256*(1+cos((L/abs(sin(thet2)))*(cos(thet2)*log(sqrt(iX.^2+iY.^2)) + sin(thet2)*atan2(iY,iX))))/2; %the log-spiral
    IMS =  IMS.*sig(cW^2-iX.^2-iY.^2, cFuz*cW/50);                                        % nice anti-alias cut off
    spdRot = 3*spdRotMax*sin((pi*(jj)/120));
    spdRot2 = 3.5*spdRotMax*sin((pi*(jj-15)/120));

elseif strcmp(type,'aliasedDisk')  % generate a disk of radius 'cW':
     IMS = 256*(...
         cW2^2 - iY.^2 - iX.^2  > 0  ...
         );
    %%%problem with the disk generation is the hardness of the boundaries,
    %%%which yields aliasing 
    %%%To overcome this, a fuzzy version i simplemented. We use a sigmoidal
    %%%function to define the boundary of the object. See next example
elseif strcmp(type,'fuzzyDisk')  % generate a disk by anti-aliasing     
    fuzLevel = cFuz*cW2/200;
      IMS = 256*(...
          sig(cW2^2 - iY.^2 - iX.^2   ,fuzLevel)  ...
          );
elseif strcmp(type,'threePatterns') % three directional patterns:
    spdRot2 = spdRotMax*sin((pi*(jj-15)/120))/2;
    fuzLevel = (3.3+3*sin((pi*(jj-15)/60)))*cFuz*cW2/20;
     IMS = 256*(...
      (1+cos(iY*0.5*16*pi).*cos(iX*cDetail*16*pi)).*sig(cW2^2-(iX+cen1).^2-iY.^2, fuzLevel) + ... //disk 1
      (1+cos(iY*16*pi)                           ).*sig(cW2^2-(iX-cen1).^2-iY.^2, fuzLevel) + ... //disk 2
      (1+cos(iX*16*pi)                           ).*sig(cW2^2-(iY-cen1).^2-iX.^2, fuzLevel)   ... //disk 3
      )/2;
end

%%%%%%%% update graphics objects %%%%%%%%%%%%%
    if ~bKillAll
        %%%%% here is where I put all my code for updating graphics
        set(hImObj,'CData',IMS);
        writeVideo(vidObj,im2frame(uint8(IMS),gray(256)));
    end
    %%%%%%%%%%% timing control %%%%%%%%%
    %This is where I make a consistent animation, by upholding deadlines
    %for rendering. This will still not be with guarantees, because matlab
    %regularly interupts execution for, e.g. memory managment.
    waitThisLong = DispFrameInterval  - toc(tStartOfFrame);
    lag = lag - min(waitThisLong,0); %if 'waitThisLong' is negative, it means we did not make the deadline.
    pause(max(waitThisLong,0.05)); %also makes matlab call drawnow, flushing out buffer.
end

% calculate average lag-time
avLag = lag/jj;
if (avLag > 0.001)
    disp(['warning. Unable to render at requested frame rate(' num2str(DispFramerate) ' frames/sec). Achieved framerate of ' num2str(round(10/(DispFrameInterval +  avLag))/10)]); 
end

%recall that we exited the loop when bKillAll was set to true. this is done
%when user indicates a kill message of the main figure window. Now we have
%to actually kill that window:
global hfig;
delete(hfig);
close(vidObj);

%%%%%%% a sigmoidal function. It does the logical operation (x>0)%%%%
function out=sig(x,fuzziness)
if nargin <2
    fuzziness = 1;end;
if (fuzziness == 0)
    out = x > 0;
else
    out= (1+erf(x./fuzziness))/2;
end

%%%%%%%%%%%%%% setting up graphics %%%%%%%%%%%%%%
%this function sets up all my graphics objects. This is called only once.
%Thereafter, these objects are manipulated by changing their internal
%states by the matlab 'set' function
function [hImObj] =setupGraphics(imSize)
global hfig;
hfig      = figure('CloseRequestFcn', @myClosefcn,'KeyPressFcn',@myKeypress,'Name','hit any key to continue');
dummyIm   = zeros(imSize);
hImObj  = imagesc(dummyIm,[1 256]); axis off;axis image;hold on; colormap gray;truesize;
title({'hit any key to continue';'Stefan M. Karlsson, email: stefan.karlsson@hh.se'});


%%%%CALLBACK FUNCTIONS %%%%%
function myKeypress(src,evnt)
global bKillAll; 
% This is where I put all my code for handling keyboard input.
if ~(strcmp(evnt.Key, 'alt')||(strcmp(evnt.Key, 'f4'))||(strcmp(evnt.Key, 'control'))||(strcmp(evnt.Key, 'shift')))
    bKillAll = 1;
    %echo what key is pressed:    
%     disp(['you pressed "' evnt.Key '" so I will save video and quit']);
end

function myClosefcn(src,evnt)
global bKillAll; 
if(bKillAll) 
    %if bKillAll is already set, then this is the second time the user 
    %tries to kill the figure. in that case, kill the figure right away
    delete(gcf);
else
    bKillAll = 1; %will cause the main loop to exit, and there I will kill the figure
%     disp(['you killed the figure, so I will save video and quit']);
end

Contact us