Customized video montages

From Dynamo
Revision as of 12:49, 11 October 2017 by Daniel Castaño (talk | contribs)
Jump to navigation Jump to search

Video montages are widely used in Dynamo to show in a single montage part of a stream of data. The user can slide on the subset of the data that is represented at a given moment. Examples of this are found in the slider GUIs used to explore sets of particles, slices inside a given volume, or selections of gold beads.

In this page, we explain how to use the underlying Dynamo objects to create your own visualization systems. We explain two possible approaches:

  • Inline montages

Can be defined easily from the command line without definition of further classes.

  • Subclassed montages

Advanced method. This method offers full flexibility at the cost of requiring from the user the creation of new classes.

Inline montages

You can use the class mbvid.guis.montages.cells.Inline, that allows inline definition of the action to be computed at each frame. For instance, imagine that you have a set of 1000 vectors, and you want to quickly explore their histograms separately. Let's generate a random data set:.

 for k=1:1000;
  myData{k} = randn(20000,1); 
end

For 1000 elements, you probably don't want to show them all in a single screen, but rather slide through the data. Thus, we create the object that represents the GUI

  gui = mbvid.guis.montages.cells.Inline(); 

we link now this object with the stream of data

   gui.setVideo(myData); 

My data is a matlab cell array in this example, but you could pass any other object that implicitly defines an stream of data. If you pass, for instance, a volume of dimensions lx x ly x lz, the stream will be defined as a succesion on lz frames.

Now, we have to tell the GUI object what to do on each frame. This is done by defining the method depictorOnAxesFcn to be an inline function of two variables. The first is a dummy variable that represents the content of the stream for a given frame. The second is the graphical axis associated to the frame in the montage. Thus:

gui.depictorOnAxesFcn = @(x,haxis) hist(haxis,x(:),100);

This command reads as: "for a frame in position i, take the position i in the stream (i.e., the i-th entry in the cell array myData associated to the gui object), and show its histogram (with 100 bins) on the axis associated to the frame".

Now we are ready to go:

  gui.show();
Customized video montage to show the histograms of a cell array of vectors.

Subclassed montages

Using this options involves a minimal comprehension of Object Oriented Programming. The underlying generic class for video montages is mbvid.guis.Montage.

Basic use of a video Montage object

Showing the GUI of an user-defined subclass myVideoMontageof mbvid.guis.Montage requires first creating the instance

gui  = myVideoMontage();

then attaching the video stream (if it is not included in the constructor)

 gui  = myVideoMontage();

and them invoking the show method:

gui.show();

Before the show operation, there are different options that you can assign beforehand:

rows
columns
width
height
title

Structure of a video montage object

A video montage object is basically the result of combining of two different types of objectc:

  • An scene manager object that runs the general layout and sliding of the scene.
  • Objects of the frameManager class that control what is depicting on each panel.

Frame manager class

This object controls the creation and updating of a frame when its representation is invoked by the scene manager in the videomontage GUI. The basic frame class is mbvid.controls.VideoMontageFrameManager. Custom frame managers need to be subclasses of this class.

Defining the action of a frame

You need to define the method createFrame in your subclass (let's call it myFrameManager). This will pass the properties 'gui' , 'frameNumber', 'hPanel' .

Linking a frame class to a GUI

In order to link a frame class to a particular class of GUI, we can assign the name of the class to the property of the GUI object.

gui.frameManagerType = 'mbvid.controls.VideoMontageFrameManager' 

The usual practice is to include this definition in the constructor method of the GUI, to ensure this assignation is ran before the GUI is shown.

Example of subclassing

In order to create a new class, you can use the usual Matlab system, or just type:

mbnew myFrameManager . mbvid.controls.montageFrameManager 

which will open the editor with this predefined content for the class @myFrameManager, created in the current directory.

 %
% class definition
%
classdef myFrameManager < mbvid.controls.montageFrameManager
  
    properties 
  
    end 
  
  
    methods 
  
       function obj=myFrameManager(varargin)
  
             obj=obj@mbvid.controls.montageFrameManager(varargin{:});
       end
              
  
    end 
  
end 

You can the define the method createFrame() inside this file, using the properties 'gui' , 'frameNumber', 'hPanel' that will be available in the obj during runtime. With

dlookfor createFrame 

you can find examples across Dynamo that implement this method in different subclasses. In our case, imagine that we want to plot a sine of the -sorted- values of the data contained in each stream entry. Moreover, in this sine we want to use a frequency that changes linearly with the number of frame. This requirement already sets us outside of the realm of inline montages, as we cannot enter the number of frame in the dependencies of the customizing function gui.depictorOnAxesFcn.

Further, for this example we introduce a modification of the plotting axes themselves, making them cover the full panel object, also overcoming the limitation of inlines of type mbvid.guis.montages.cells.Inline. We just provide the class myFrameManager with the method createFrame

       function createFrame(obj);
           haxis = axes('Parent',obj.hPanel);
           
           set(haxis,'Position',[0,0,1,1]);
           
           myVideo = obj.gui.getVideo();
           myData = myVideo.read(obj.frameNumber);  
           
           % change the data differently for each frame
           representedData = sin(sort(myData)*obj.frameNumber);
           plot(representedData,'Parent',haxis);
       end 

This can be typed into the class file itself, or in the class folder (after declaring the method signature in the class file). With this definition, we could use as basis the general class mbvid.guis.VideoMontage.

You also need to provide and updateFrame, which will be triggered each time we change the scene. This is the actual art of designing video montages and specifically subclasses of frameManager. Here, you should normally provide your class with further properties to store and reuse graphic elements or already available computations, so that they don't need to be recreated each time new frames are generated or recalled.... but in simple applications, you can also avoid over-engineering by simply invoking again the creation of the frame.

function updateFrame(obj); % Just recreates the frame % Not recommended for performance-critic applications obj.createFrame(); end


a = mbvid.guis.VideoMontage();

but linking it to the type of frame behaviour we just defined:

a.frameManagerType = 'myFrameManager'; 

If we now link the stream of data that we defined previously:

a.setVideo(myData);

we can now show the video montage:

a.show();
Customized video montage to show the histograms of a cell array of vectors.