changeset 831:d85ddd5300a9

strel: implement SE decomposition for the octagon shape. * @strel/getsequence.m: implement sequence to perform SE decomposition of an octagon shape. * @strel/strel.m: change input check for the octagon shape to be a non-negative multiple of 3 (so it also accepts a value of 0), and implement that special case. Convert unecessary %!shared block into different %test blocks. Add more tests for the octagon shape.
author Carnë Draug <carandraug@octave.org>
date Mon, 11 Nov 2013 22:08:00 +0000
parents 754a6f127d0d
children 9ea56b150093
files inst/@strel/getsequence.m inst/@strel/strel.m
diffstat 2 files changed, 171 insertions(+), 104 deletions(-) [+]
line wrap: on
line diff
--- a/inst/@strel/getsequence.m
+++ b/inst/@strel/getsequence.m
@@ -1,4 +1,5 @@
 ## Copyright (C) 2012 Roberto Metere <roberto@metere.it>
+## Copyright (C) 2013 Carnë Draug <carandraug@octave.org>
 ##
 ## This program 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
@@ -38,9 +39,21 @@
         vec_size(idx) = size (se.nhood, idx);
         se.seq{idx}   = strel ("arbitrary", true (vec_size));
       endfor
+    elseif (strcmp (se.shape, "octagon") && se.opt.apothem > 0)
+      persistent octagon_template = get_octagon_template ();
+      se.seq = repmat (octagon_template, se.opt.apothem /3, 1);
     else
         se.seq{1,1} = se;
     endif
   endif
 
 endfunction
+
+function template = get_octagon_template ()
+  template = repmat ({false(3)}, 4, 1);
+  template{1}(2,:)     = true;
+  template{2}(:,2)     = true;
+  template{3}([1 5 9]) = true;
+  template{4}([3 5 7]) = true;
+  template = cellfun (@(x) strel ("arbitrary", x), template, "UniformOutput", false);
+endfunction
--- a/inst/@strel/strel.m
+++ b/inst/@strel/strel.m
@@ -92,8 +92,8 @@
 ## @end deftypefn
 ## @deftypefn {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
-## the octagon.
+## non-negative integer, multiple of 3, that specifies the distance from the
+## origin to the sides of the octagon.
 ##
 ## @end deftypefn
 ## @deftypefn {Function File} {} strel ("pair", @var{offset})
@@ -413,24 +413,28 @@
 
     case "octagon"
       if (numel (varargin) == 1)
-        apothem = varargin{1};
+        SE.opt.apothem = apothem = varargin{1};
       else
         error ("strel: no APOTHEM specified for octagon shape");
       endif
-      if (! is_positive_integer (apothem) || mod (apothem, 3) != 0)
+      if (! is_nonnegative_integer (apothem) || mod (apothem, 3) != 0)
         error ("strel: APOTHEM must be a positive integer multiple of 3");
       endif
 
       ## we look at it as 9 blocks. North AND South are the same and West TO
       ## East as well. We make the corner for NorthEast and rotate it for the
       ## other corners
-      cwide    = apothem/3*2 + 1;
-      iwide    = apothem/3*2 - 1;
-      N_and_S  = true ([cwide iwide]);
-      corner   = tril (true (cwide));
-      SE.nhood = [rotdim(corner), N_and_S, corner;
-                  true([iwide (2*apothem + 1)]);
-                  transpose(corner), N_and_S, rotdim(corner, -1)];
+      if (apothem == 0)
+        SE.nhood = true (1);
+      else
+        cwide    = apothem/3*2 + 1;
+        iwide    = apothem/3*2 - 1;
+        N_and_S  = true ([cwide iwide]);
+        corner   = tril (true (cwide));
+        SE.nhood = [rotdim(corner), N_and_S, corner;
+                    true([iwide (2*apothem + 1)]);
+                    transpose(corner), N_and_S, rotdim(corner, -1)];
+      endif
       SE.flat  = true;
 
     case "pair"
@@ -517,6 +521,10 @@
   retval = isscalar (val) && isnumeric (val) && val > 0 && fix (val) == val;
 endfunction
 
+function retval = is_nonnegative_integer (val)
+  retval = isscalar (val) && isnumeric (val) && val >= 0 && fix (val) == val;
+endfunction
+
 function retval = sign0positive (val)
   if (sign (val) == -1)
     retval = -1;
@@ -525,24 +533,29 @@
   endif
 endfunction
 
-%!shared shape, height
-%! shape  = [0 0 0 1];
-%!assert (getnhood (strel (shape)), logical (shape));
-%!assert (getnhood (strel ("arbitrary", shape)), logical (shape));
+%!test
+%! shape  = logical ([0 0 0 1]);
+%! assert (getnhood (strel (shape)), shape);
+%! assert (getnhood (strel ("arbitrary", shape)), shape);
+%!
 %! height = [0 0 0 3];
-%!assert (getnhood (strel ("arbitrary", shape, height)), logical (shape));
-%!assert (getheight (strel ("arbitrary", shape, height)), height);
-%! shape = [0 0 1];
+%! assert (getnhood (strel ("arbitrary", shape, height)), shape);
+%! assert (getheight (strel ("arbitrary", shape, height)), height);
+
+%!test
+%! shape = logical ([0 0 1]);
 %! height = [-2 1 3];  ## this works for matlab compatibility
-%!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];
+%! assert (getnhood (strel ("arbitrary", shape, height)), shape);
+%! assert (getheight (strel ("arbitrary", shape, height)), height);
+
+%!test
+%! shape = logical ([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
@@ -550,91 +563,130 @@
 %!            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, 0.0001);
-%! 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
-%!          0 1 1 1 1 1 0
-%!          0 0 1 1 1 0 0
-%!          0 0 0 1 0 0 0];
-%!assert (getnhood (strel ("diamond", 3)), logical (shape));
-%! 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];
-%!assert (getnhood (strel ("disk", 3)), logical (shape));
-%! shape = [1 1 1];
-%!assert (getnhood (strel ("line", 3.9, 20.17)), logical (shape));
-%! shape = [0 0 1
-%!          0 1 0
-%!          1 0 0];
-%!assert (getnhood (strel ("line", 3.9, 20.18)), logical (shape));
-%! shape = [1 0 0 0 0 0 0 0 0
-%!          0 1 0 0 0 0 0 0 0
-%!          0 0 1 0 0 0 0 0 0
-%!          0 0 1 0 0 0 0 0 0
-%!          0 0 0 1 0 0 0 0 0
-%!          0 0 0 0 1 0 0 0 0
-%!          0 0 0 0 0 1 0 0 0
-%!          0 0 0 0 0 0 1 0 0
-%!          0 0 0 0 0 0 1 0 0
-%!          0 0 0 0 0 0 0 1 0
-%!          0 0 0 0 0 0 0 0 1];
-%!assert (getnhood (strel ("line", 14, 130)), logical (shape));
-%! shape = [0 0 1 1 1 0 0
-%!          0 1 1 1 1 1 0
-%!          1 1 1 1 1 1 1
-%!          1 1 1 1 1 1 1
-%!          1 1 1 1 1 1 1
-%!          0 1 1 1 1 1 0
-%!          0 0 1 1 1 0 0];
-%!assert (getnhood (strel ("octagon", 3)), logical (shape));
-%! shape = [1;1;0];
-%!assert (getnhood (strel ("pair", [-1 0])), logical (shape));
-%! shape = [1 0 0 0 0 0 0
-%!          0 0 0 1 0 0 0
-%!          0 0 0 0 0 0 0];
-%!assert (getnhood (strel ("pair", [-1 -3])), logical (shape));
-%! shape = [0 0 0 0 0 0 0
-%!          0 0 0 0 0 0 0
-%!          0 0 0 1 0 0 0
-%!          0 0 0 0 0 0 0
-%!          0 0 0 0 0 0 1];
-%!assert (getnhood (strel ("pair", [2 3])), logical (shape));
-%!assert (getnhood (strel ("rectangle", [10 5])), true (10, 5));
-%!assert (getnhood (strel ("square", 5)), true (5));
+%! assert (getnhood (strel ("ball", 3, 1)), shape);
+%! assert (getheight (strel ("ball", 3, 1)), height, 0.0001);
+
+%!test
+%! shape = logical ([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
+%!                   0 1 1 1 1 1 0
+%!                   0 0 1 1 1 0 0
+%!                   0 0 0 1 0 0 0]);
+%! assert (getnhood (strel ("diamond", 3)), shape);
+
+%!test
+%! shape = logical ([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]);
+%! assert (getnhood (strel ("disk", 3)), shape);
+
+%!test
+%! shape = logical ([1 1 1]);
+%! assert (getnhood (strel ("line", 3.9, 20.17)), shape);
+%! shape = logical ([0 0 1
+%!                   0 1 0
+%!                   1 0 0]);
+%! assert (getnhood (strel ("line", 3.9, 20.18)), shape);
+%! shape = logical ([1 0 0 0 0 0 0 0 0
+%!                   0 1 0 0 0 0 0 0 0
+%!                   0 0 1 0 0 0 0 0 0
+%!                   0 0 1 0 0 0 0 0 0
+%!                   0 0 0 1 0 0 0 0 0
+%!                   0 0 0 0 1 0 0 0 0
+%!                   0 0 0 0 0 1 0 0 0
+%!                   0 0 0 0 0 0 1 0 0
+%!                   0 0 0 0 0 0 1 0 0
+%!                   0 0 0 0 0 0 0 1 0
+%!                   0 0 0 0 0 0 0 0 1]);
+%! assert (getnhood (strel ("line", 14, 130)), shape);
+
+%!test
+%! se = strel ("octagon", 0);
+%! seq = getsequence (se);
+%! assert (getnhood (se), true (1));
+%! assert (getnhood (seq(1)), true (1));
+%!
+%! se = strel ("octagon", 3);
+%! seq = getsequence (se);
+%! shape = logical ([0 0 1 1 1 0 0
+%!                   0 1 1 1 1 1 0
+%!                   1 1 1 1 1 1 1
+%!                   1 1 1 1 1 1 1
+%!                   1 1 1 1 1 1 1
+%!                   0 1 1 1 1 1 0
+%!                   0 0 1 1 1 0 0]);
+%! assert (getnhood (se), shape);
+%! assert (size (seq), [4 1]);
+%!
+%! templ1 = logical ([0 0 0; 1 1 1; 0 0 0]);
+%! templ2 = logical ([0 1 0; 0 1 0; 0 1 0]);
+%! templ3 = logical ([1 0 0; 0 1 0; 0 0 1]);
+%! templ4 = logical ([0 0 1; 0 1 0; 1 0 0]);
+%! assert ({getnhood(seq(1)) getnhood(seq(2)) getnhood(seq(3)) getnhood(seq(4))},
+%!         {templ1 templ2 templ3 templ4});
+
+%!test
+%! seq = getsequence (strel ("octagon", 21));
+%! assert (size (seq), [28 1]);
+%! assert (arrayfun (@(x) getnhood (seq(x)), 1:4:25, "UniformOutput", false),
+%!         repmat ({templ1}, 1, 7));
+%! assert (arrayfun (@(x) getnhood (seq(x)), 2:4:26, "UniformOutput", false),
+%!         repmat ({templ2}, 1, 7));
+%! assert (arrayfun (@(x) getnhood (seq(x)), 3:4:27, "UniformOutput", false),
+%!         repmat ({templ3}, 1, 7));
+%! assert (arrayfun (@(x) getnhood (seq(x)), 4:4:28, "UniformOutput", false),
+%!         repmat ({templ4}, 1, 7));
+
+%!test
+%! shape = logical ([1 1 0]');
+%! assert (getnhood (strel ("pair", [-1 0])), shape);
+%! shape = logical ([1 0 0 0 0 0 0
+%!                   0 0 0 1 0 0 0
+%!                   0 0 0 0 0 0 0]);
+%! assert (getnhood (strel ("pair", [-1 -3])), shape);
+%! shape = logical ([0 0 0 0 0 0 0
+%!                   0 0 0 0 0 0 0
+%!                   0 0 0 1 0 0 0
+%!                   0 0 0 0 0 0 0
+%!                   0 0 0 0 0 0 1]);
+%! assert (getnhood (strel ("pair", [2 3])), shape);
+
+%!test
+%! assert (getnhood (strel ("rectangle", [10 5])), true (10, 5));
+%! assert (getnhood (strel ("square", 5)), true (5));
 
 ## test how @strel/getsequence and indexing works fine
 %!shared se, seq
 %! se = strel ("square", 5);
 %! seq = getsequence (se);
-%!assert (class (se(1)),  "strel")
-%!assert (class (se(1,1)),"strel")
-%!assert (class (seq),    "strel")
-%!assert (class (seq(1)), "strel")
-%!assert (class (seq(2)), "strel")
-%!assert (numel (se), 1)
-%!assert (numel (seq), 2)
-%!assert (getnhood (seq(1)), true (5, 1))
-%!assert (getnhood (seq(2)), true (1, 5))
-%!assert (size (se),  [1 1])
-%!assert (size (seq), [2 1])
-%!assert (isscalar (se),  true)
-%!assert (isscalar (seq), false)
-%!error se(2);
-%!error seq(3);
+%! assert (class (se(1)),  "strel")
+%! assert (class (se(1,1)),"strel")
+%! assert (class (seq),    "strel")
+%! assert (class (seq(1)), "strel")
+%! assert (class (seq(2)), "strel")
+%! assert (numel (se), 1)
+%! assert (numel (seq), 2)
+%! assert (getnhood (seq(1)), true (5, 1))
+%! assert (getnhood (seq(2)), true (1, 5))
+%! assert (size (se),  [1 1])
+%! assert (size (seq), [2 1])
+%! assert (isscalar (se),  true)
+%! assert (isscalar (seq), false)
+%!error <index out of bounds> se(2);
+%!error <index out of bounds> seq(3);
 
 ## test reflection
-%!shared se, ref
+%!test
 %! se = strel ("arbitrary", [1 0 0; 1 1 0; 0 1 0], [2 0 0; 3 1 0; 0 3 0]);
 %! ref = reflect (se);
-%!assert (getnhood (ref), logical([0 1 0; 0 1 1; 0 0 1]));
-%!assert (getheight (ref), [0 3 0; 0 1 3; 0 0 2]);
+%! assert (getnhood (ref), logical([0 1 0; 0 1 1; 0 0 1]));
+%! assert (getheight (ref), [0 3 0; 0 1 3; 0 0 2]);
 
 ## test input validation
 %!error strel()
@@ -646,7 +698,9 @@
 %!error strel("diamond", -3)
 %!error strel("disk", -3)
 %!error strel("line", 0, 45)
-%!error strel("octagon", 4)
+%!error <positive integer multiple of 3> strel("octagon", 3.5)
+%!error <positive integer multiple of 3> strel("octagon", 4)
+%!error <positive integer multiple of 3> strel("octagon", -1)
 %!error strel("pair", [45 67 90])
 %!error strel("rectangle", 2)
 %!error strel("rectangle", [2 -5])