changeset 26212:2be1833a93a5

movie.m: New function (patch #9363) * NEWS: Announce new function. * scripts/image/movie.m: New function file. * scripts/image/module.mk: Add movie.m to build system. * getframe.m: Add movie to seealso links. * image.txi: Add movie DOCSTRING. Reorganize part of "Representing Images" section.
author Pantxo Diribarne <pantxo.diribarne@gmail.com>
date Sun, 28 May 2017 13:42:02 +0200
parents 69bd0cfbd123
children ff0eadb417ec
files NEWS doc/interpreter/image.txi scripts/image/getframe.m scripts/image/module.mk scripts/image/movie.m
diffstat 5 files changed, 236 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed Dec 12 15:01:21 2018 -0800
+++ b/NEWS	Sun May 28 13:42:02 2017 +0200
@@ -164,6 +164,7 @@
       matlab.lang.makeUniqueStrings
       matlab.lang.makeValidName
       movegui
+      movie
       openfig
       ordeig
       savefig
--- a/doc/interpreter/image.txi	Wed Dec 12 15:01:21 2018 -0800
+++ b/doc/interpreter/image.txi	Sun May 28 13:42:02 2017 +0200
@@ -140,9 +140,10 @@
 an RGB color.  The color map must be of class @code{double} with values
 between 0 and 1.
 
-@DOCSTRING(im2double)
+The following convenience functions are available for conversion between image 
+formats.
 
-@DOCSTRING(iscolormap)
+@DOCSTRING(im2double)
 
 @DOCSTRING(gray2ind)
 
@@ -152,14 +153,27 @@
 
 @DOCSTRING(ind2rgb)
 
+Octave also provides tools to produce and work with movie frame structures. 
+Those structures encapsulate the image data (@qcode{"cdata"} field) together 
+with the corresponding colormap (@qcode{"colormap"} field).
+
 @DOCSTRING(getframe)
 
+@DOCSTRING(movie)
+
 @DOCSTRING(frame2im)
 
 @DOCSTRING(im2frame)
 
+The @code{colormap} function is used to change the colormap of the current axes or figure.
+
 @DOCSTRING(colormap)
 
+@DOCSTRING(iscolormap)
+
+The following functions return predefined colormaps, the same that can be 
+requested by name using the @code{colormap} function. 
+
 @DOCSTRING(rgbplot)
 
 @DOCSTRING(autumn)
--- a/scripts/image/getframe.m	Wed Dec 12 15:01:21 2018 -0800
+++ b/scripts/image/getframe.m	Sun May 28 13:42:02 2017 +0200
@@ -41,7 +41,7 @@
 ## the figure to be captured.  Regardless of the figure @qcode{"units"}
 ## property, @var{rect} must be defined in @strong{pixels}.
 ##
-## @seealso{im2frame, frame2im}
+## @seealso{im2frame, frame2im, movie}
 ## @end deftypefn
 
 function frame = getframe (h = [], rect = [])
--- a/scripts/image/module.mk	Wed Dec 12 15:01:21 2018 -0800
+++ b/scripts/image/module.mk	Sun May 28 13:42:02 2017 +0200
@@ -46,6 +46,7 @@
   %reldir%/iscolormap.m \
   %reldir%/jet.m \
   %reldir%/lines.m \
+  %reldir%/movie.m \
   %reldir%/ocean.m \
   %reldir%/pink.m \
   %reldir%/prism.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/image/movie.m	Sun May 28 13:42:02 2017 +0200
@@ -0,0 +1,217 @@
+## Copyright (C) 2017 Pantxo Diribarne
+## 
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} movie (@var{mov})
+## @deftypefnx {} {} movie (@var{mov}, @var{n})
+## @deftypefnx {} {} movie (@var{mov}, @var{n}, @var{fps})
+## @deftypefnx {} {} movie (@var{h}, @dots{})
+## Play a movie defined by an array of frame structures.
+##
+## The movie @var{mov} must be a struct array of frames with fields
+## @qcode{"cdata"} and @qcode{"colormap"}, as returned by the @code{getframe}
+## function.  By default all images are displayed once, at 12 fps, in the
+## current axes.
+##
+## The optional argument @var{n} is a scalar or vector of integers that
+## controls the number of times the movie is displayed and which particular
+## frames are shown:
+##
+## @table @asis
+## @item First element:
+##
+## @table @asis
+## @item @var{n}(1) > 0
+## Play the movie @var{n}(1) times.
+##
+## @item @var{n}(1) < 0
+## Play the movie @code{abs (@var{n}(1)} times alternatively in forward and
+## backward order.
+## @end table
+##
+## @item Other elements (if any):
+## Indices of the frames in @var{mov} that will be displayed.
+## @end table
+##
+## If the first argument is a handle to a figure or axes @var{h}, the movie is
+## played in that figure or axes instead of the current axes.
+##
+## @seealso{getframe, im2frame, frame2im}
+## @end deftypefn
+
+function movie (varargin)
+
+  if (nargin == 0)
+    print_usage ();
+  endif
+
+  ## Extract possible handle argument
+  hax = [];
+  if (isaxes (varargin{1}))
+    hax = varargin{1};
+    varargin(1) = [];
+  elseif (isfigure (varargin{1}))
+    hax = get (varargin{1}, "currentaxes");
+    if (isempty (hax))
+      hax = axes ("parent", varargin{1});
+    endif
+    varargin(1) = [];
+  endif
+
+  ## Extract other arguments
+  n = 1;
+  fps = 12;
+  idx = [];
+  nargs = numel (varargin);
+  if (nargs == 0)
+    print_usage ();
+  elseif (nargs >= 1)
+    mov = varargin{1};
+    if (! isfield (mov, "cdata") || ! isfield (mov, "colormap"))
+      error ("movie: MOV must be a frame struct array");
+    endif
+
+    if (nargs >= 2)
+      n = varargin{2};
+      if (! isindex (abs (n(1))))
+        error ("movie: N must be a non-zero integer");
+      elseif (! isscalar (n))
+        idx = n(2:end)(:)';
+        n = n(1);
+        if (! isindex (idx, numel (mov)))
+          error (["movie: All elements N(2:end) must be valid indices ", ...
+                  "into the MOV struct array"]);
+
+        endif
+      endif
+        
+      if (nargs >= 3)
+        fps = varargin{3};
+        if (! (isnumeric (fps) && isscalar (fps) && fps > 0))
+          error ("movie: FPS must be a numeric scalar > 0");
+        endif
+      endif
+    endif
+  endif
+
+  if (isempty (hax))
+    hax = gca ();
+  endif
+
+  ## Build the list of frames to be displayed
+  if (isempty (idx))
+    idx = (1:numel (mov));
+  endif
+
+  if (n > 0)
+    idx = repmat (idx, 1, n);
+  else
+    n = -n;
+    tmp = repmat ([idx fliplr(idx)], 1, fix (n/2));
+    if (fix (n/2) != n/2)
+      idx = [tmp, idx];
+    else
+      idx = tmp;
+    endif
+  endif
+
+  tau = 1/fps;
+  set (hax, "ydir", "reverse", "visible", "off");
+  tic ();
+  him = image ("parent", hax, "cdata", mov(1).cdata);
+  for ii = idx
+    pause (tau - toc ());
+    tic ();
+    if (! isempty (mov(ii).colormap))
+      set (hax, "colormap", mov(ii).colormap)
+    endif
+    set (him, "cdata", mov(ii).cdata);
+  endfor
+  
+endfunction
+
+
+%!demo
+%! nframes = 20;
+%! colors = jet (nframes);
+%! baseim = ones (20, 20, 3, "uint8");
+%! mov(nframes) = struct ("cdata", [], "colormap", []);
+%! for ii = 1:nframes
+%!   im = baseim * 255;
+%!   im(:,ii,1) = colors(ii,1) * 255;
+%!   im(:,ii,2) = colors(ii,2) * 255;
+%!   im(:,ii,3) = colors(ii,3) * 255;
+%!   mov(ii).cdata = im;
+%! endfor
+%! clf ();
+%! title "Play movie forward 2 times"
+%! movie (mov, 2);
+
+%!demo
+%! nframes = 20;
+%! colors = jet (nframes);
+%! baseim = ones (20, 20, 3, "uint8");
+%! mov(nframes) = struct ("cdata", [], "colormap", []);
+%! for ii = 1:nframes
+%!   im = baseim * 255;
+%!   im(:,ii,1) = colors(ii,1) * 255;
+%!   im(:,ii,2) = colors(ii,2) * 255;
+%!   im(:,ii,3) = colors(ii,3) * 255;
+%!   mov(ii).cdata = im;
+%! endfor
+%! clf ();
+%! title "Play movie forward and backward 5 times at 25 fps"
+%! movie (mov, -5, 25);
+
+%!demo
+%! nframes = 20;
+%! colors = jet (nframes);
+%! baseim = ones (20, 20, 3, "uint8");
+%! mov(nframes) = struct ("cdata", [], "colormap", []);
+%! for ii = 1:nframes
+%!   im = baseim * 255;
+%!   im(:,ii,1) = colors(ii,1) * 255;
+%!   im(:,ii,2) = colors(ii,2) * 255;
+%!   im(:,ii,3) = colors(ii,3) * 255;
+%!   mov(ii).cdata = im;
+%! endfor
+%! clf ();
+%! title "Play downsampled movie 5 times" 
+%! movie (mov, [5 1:3:nframes]);
+
+%!demo
+%! clf ();
+%! z = sombrero ();
+%! hs = surf (z);
+%! axis manual
+%! nframes = 50;
+%! mov(nframes) = struct ("cdata", [], "colormap", []);
+%! for ii = 1:nframes
+%!   set (hs, "zdata", z * sin (2*pi*ii/nframes));
+%!   mov(ii) = getframe ();
+%! endfor
+%! clf ();
+%! movie (mov, 5, 25);
+
+## Test input validation
+%!error movie ()
+%!error <MOV must be a frame struct array> movie ({2})
+%!error <N must be a non-zero integer>
+%! movie (struct ("cdata", [], "colormap", []), 2.3);
+%!error <N must be a non-zero integer>
+%! movie (struct ("cdata", [], "colormap", []), [2.3 -6]);