changeset 11664:dba7f31a2ab3 octave-forge

strel: implement ball and 3dline options. Patch by Roberto Metere <roberto@metere.it>
author carandraug
date Sun, 28 Apr 2013 03:32:20 +0000
parents 3863d5c25ae3
children 7ffd3162121b
files main/image/inst/@strel/strel.m
diffstat 1 files changed, 121 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/main/image/inst/@strel/strel.m	Sun Apr 28 02:40:25 2013 +0000
+++ b/main/image/inst/@strel/strel.m	Sun Apr 28 03:32:20 2013 +0000
@@ -45,6 +45,11 @@
 ## @end group
 ## @end example
 ##
+## @deftypefnx {Function File} {} strel ("ball", @var{radius}, @var{height})
+## Create ball shaped @var{nonflat} structuring element.  @var{radius} must be a
+## nonnegative integer that specifies the ray of a circle in X-Y plane.  @var{height}
+## is a real number that specifies the height of the center of the circle.
+##
 ## @deftypefnx {Function File} {} strel ("cube", @var{edge})
 ## Create cube shaped @var{flat} structuring element.  @var{edge} must be a
 ## positive integer that specifies the length of its edges.  This shape meant to
@@ -63,6 +68,12 @@
 ## Create line shaped flat structuring element.  @var{len} must be a positive
 ## real number.  @var{deg} must be a real number.
 ##
+## @deftypefnx {Function File} {} strel ("3dline", @var{len}, @var{alpha}, @var{phi})
+## Create line shaped flat structuring element in 3D.  @var{len} must be a positive
+## real number.  @var{alpha} is the angle from X-axis to X-Y projection of the line
+## and must be a real number.  @var{phi} is the angle from Z-axis to the line and
+## must be a real number.
+##
 ## @deftypefnx {Function File} {} strel ("octagon", @var{apothem})
 ## Create octagon shaped flat structuring element.  @var{apothem} must be a
 ## positive integer that specifies the distance from the origin to the sides of
@@ -157,8 +168,26 @@
         error ("strel: HEIGHT must be a finite real matrix of the same size as NHOOD");
       endif
 
-#    case "ball"
-      ## TODO implement ball shape
+    case "ball"
+      if (numel (varargin) == 2)
+        radius = varargin{1};
+        height = varargin{2};
+      else
+        ## TODO implement third option for number of periodic lines approximation
+        error ("strel: a ball shape needs 2 arguments");
+      endif
+      if (! is_positive_integer (radius))
+        error ("strel: RADIUS must be a positive integer");
+      elseif (! (isscalar (height) && isnumeric (height)))
+        error ("strel: HEIGHT must be a real number");
+      endif
+
+      # Ellipsoid: (x/radius)^2 + (y/radius)^2 + (z/height)^2 = 1
+      # We need only the 1 cells of SE.nhood
+      [x, y] = meshgrid (-radius:radius, -radius:radius);
+      SE.nhood = ((x.^2 + y.^2) <= radius^2); # X-Y circle
+      SE.height = height / radius * SE.nhood .* sqrt (radius^2 - x .^2 - y.^2);
+      SE.flat = false;
 
     case "cube"
       if (numel (varargin) == 1)
@@ -167,7 +196,7 @@
         error ("strel: no EDGE specified for cube shape");
       endif
       if (! is_positive_integer (SE.opt.edge))
-        error ("strel: EDGE value must be positive integers");
+        error ("strel: EDGE value must be a positive integer");
       endif
 
       SE.nhood = true (SE.opt.edge, SE.opt.edge, SE.opt.edge);
@@ -192,7 +221,7 @@
       if (numel (varargin) == 1)
         radius = varargin{1};
       else
-        ## TODO implement second option for number of periodic lines
+        ## TODO implement second option for number of periodic lines approximation
         error ("strel: no RADIUS specified for disk shape");
       endif
       if (! is_positive_integer (radius))
@@ -265,7 +294,69 @@
 
       SE.flat = true;
 
-   case "octagon"
+    case "3dline"
+      if (numel (varargin) == 3)
+        linelen = varargin{1};
+        alpha = varargin{2};
+        phi = varargin{3};
+      else
+        error ("strel: a line shape needs 3 arguments");
+      endif
+      if (! (isscalar (linelen) && isnumeric (linelen) && linelen > 0))
+        error ("strel: LEN must be a positive real number");
+      elseif (! (isscalar (alpha) && isnumeric (alpha)))
+        error ("strel: ALPHA must be a real number");
+      elseif (! (isscalar (phi) && isnumeric (phi)))
+        error ("strel: PHI must be a real number");
+      endif
+
+      ## This is a first implementation
+      # Stroke line from cells (x1, y1, z1) to (x2, y2, z2)
+      alpha *= pi / 180;
+      phi *= pi / 180;
+      x1 = y1 = z1 = 0;
+      x2 = round (linelen * sin (phi) * cos (alpha));
+      y2 = round (linelen * sin (phi) * sin (alpha));
+      z2 = round (linelen * cos (phi));
+      # Adjust x2, y2, z2 to have one central cell
+      x2 += (! mod (x2, 2)) * sign0positive (x2);
+      y2 += (! mod (y2, 2)) * sign0positive (y2);
+      z2 += (! mod (z2, 2)) * sign0positive (z2);
+      # Invert x
+      x2 = -x2;
+
+      # Tanslate parallelepiped to be in positive quadrant
+      if (x2 < 0)
+        x1 -= x2;
+        x2 -= x2;
+      endif
+      if (y2 < 0)
+        y1 -= y2;
+        y2 -= y2;
+      endif
+      if (z2 < 0)
+        z1 -= z2;
+        z2 -= z2;
+      endif
+
+      # Compute index2es
+      dim = abs ([(x2 - x1) (y2 - y1) (z2 - z1)]);
+      m = max (dim);
+      base = meshgrid (0:m - 1,1) .+ 0.5;
+      a = floor ((x2 - x1)/m .* base);
+      b = floor ((y2 - y1)/m .* base);
+      c = floor ((z2 - z1)/m .* base);
+      # Adjust indexes to be valid
+      a -= min (a) - 1;
+      b -= min (b) - 1;
+      c -= min (c) - 1;
+      indexes = sub2ind (dim, a, b, c);
+
+      SE.nhood = false (dim);
+      SE.nhood(indexes) = true;
+      SE.flat = true;
+
+    case "octagon"
       if (numel (varargin) == 1)
         apothem = varargin{1};
       else
@@ -371,6 +462,14 @@
   retval = isscalar (val) && isnumeric (val) && val > 0 && fix (val) == val;
 endfunction
 
+function retval = sign0positive (val)
+  if (sign (val) == -1)
+    retval = -1;
+  else
+    retval = 1;
+  endif
+endfunction
+
 %!shared shape, height
 %! shape  = [0 0 0 1];
 %!assert (getnhood (strel (shape)), logical (shape));
@@ -383,6 +482,22 @@
 %!assert (getnhood (strel ("arbitrary", shape, height)), logical (shape));
 %!assert (getheight (strel ("arbitrary", shape, height)), height);
 %! shape = [0 0 0 1 0 0 0
+%!          0 1 1 1 1 1 0
+%!          0 1 1 1 1 1 0
+%!          1 1 1 1 1 1 1
+%!          0 1 1 1 1 1 0
+%!          0 1 1 1 1 1 0
+%!          0 0 0 1 0 0 0];
+%! height = [ 0.00000   0.00000   0.00000   0.00000   0.00000   0.00000   0.00000
+%!            0.00000   0.33333   0.66667   0.74536   0.66667   0.33333   0.00000
+%!            0.00000   0.66667   0.88192   0.94281   0.88192   0.66667   0.00000
+%!            0.00000   0.74536   0.94281   1.00000   0.94281   0.74536   0.00000
+%!            0.00000   0.66667   0.88192   0.94281   0.88192   0.66667   0.00000
+%!            0.00000   0.33333   0.66667   0.74536   0.66667   0.33333   0.00000
+%!            0.00000   0.00000   0.00000   0.00000   0.00000   0.00000   0.00000]
+%!assert (getnhood (strel ("ball", 3, 1)), logical (shape));
+%!assert (getheight (strel ("ball", 3, 1)), height);
+%! shape = [0 0 0 1 0 0 0
 %!          0 0 1 1 1 0 0
 %!          0 1 1 1 1 1 0
 %!          1 1 1 1 1 1 1
@@ -466,6 +581,7 @@
 %!error strel("arbitrary", "stuff")
 %!error strel("arbitrary", [0 0 1], [2 0 1; 4 5 1])
 %!error strel("arbitrary", [0 0 1], "stuff")
+%!error strel("ball", -3, 1)
 %!error strel("diamond", -3)
 %!error strel("disk", -3)
 %!error strel("line", 0, 45)