changeset 890:3d1d76c830c6

conndef: rewrite as C++ class to be easily used by C++ classes. * inst/conndef.m: removed and replaced by C++ version. Help test and tests were reused. * src/conndef.h: definition of new conndef C++ class. * src/conndef.cc: implementation of the conndef C++ class and an Octave function which simply calls the C++ constructor. Adds alternative input to specify number of connected elements rather than ndims (so it can be used by functions such as bwlabeln, or bwconncomp). * src/Makefile: update for conndef. * COPYING: update list of conndef files. * NEWS: make note of new interface to conndef.
author Carnë Draug <carandraug@octave.org>
date Wed, 01 Oct 2014 01:05:31 +0100
parents ea45a8e63169
children a65390dffc5a
files COPYING NEWS inst/conndef.m src/Makefile src/conndef.cc src/conndef.h
diffstat 6 files changed, 311 insertions(+), 128 deletions(-) [+]
line wrap: on
line diff
--- a/COPYING
+++ b/COPYING
@@ -44,7 +44,6 @@
 inst/col2im.m                           GPLv3+
 inst/colfilt.m                          GPLv3+
 inst/colorgradient.m                    public domain
-inst/conndef.m                          GPLv3+
 inst/corr2.m                            GPLv3+
 inst/cp2tform.m                         GPLv3+
 inst/edge.m                             GPLv3+
@@ -149,6 +148,8 @@
 src/bwdist.cc                           GPLv3+
 src/bwfill.cc                           GPLv3+
 src/bwlabeln.cc                         GPLv3+
+src/conndef.cc                          GPLv3+
+src/conndef.h                           GPLv3+
 src/__custom_gaussian_smoothing__.cc    GPLv3+
 src/graycomatrix.cc                     FreeBSD
 src/hough_line.cc                       FreeBSD
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,10 @@
     imperspectivewarp functions now use 0 instead of NA for the default
     extrapolation value.
 
+ ** The conndef function has a new signature with a single argument to
+    specify the number of elements connected to the center of the
+    connectivity array.
+
  ** Deprecated functions.
 
     The following functions were deprecated in image 2.2.0 and have been
deleted file mode 100644
--- a/inst/conndef.m
+++ /dev/null
@@ -1,126 +0,0 @@
-## Copyright (C) 2004 Josep Mones i Teixidor <jmones@puntbarra.com>
-##
-## 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
-## Foundation; either version 3 of the License, or (at your option) any later
-## version.
-##
-## This program 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
-## this program; if not, see <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn {Function File} {} conndef (@var{num_dims}, @var{type})
-## Create connectivity array.
-##
-## Creates a binary matrix of @var{num_dims} dimensions for morphological
-## operations, where elements with a value of 1 are considered connected
-## to the center element (a connectivity array).
-##
-## There are two possible @var{type}s of connectivity array, defined with
-## the strings:
-## @table @qcode
-## @item minimal
-## Neighbours touch the central element on a (@var{num_dims}-1)-dimensional
-## surface.
-## @item maximal
-## Neighbours touch the central element in any way. Equivalent to
-## @code{ones (repmat (3, 1, @var{num_dims}))}.
-## @end table
-##
-## @seealso{iptcheckconn, strel}
-## @end deftypefn
-
-function conn = conndef (num_dims, conntype)
-
-  if (nargin != 2)
-    print_usage ();
-  elseif (! isnumeric (num_dims) || ! isscalar (num_dims) || num_dims <= 0 ||
-          fix (num_dims) != num_dims)
-    error ("conndef: NUM_DIMS must be a positive integer");
-  elseif (! ischar (conntype))
-    error ("conndef: CONNTYPE must be a string with type of connectivity")
-  endif
-
-  if (strcmpi (conntype, "minimal"))
-    if (num_dims == 1)
-      ## This case does not exist in Matlab
-      conn = [1; 1; 1];
-    elseif (num_dims == 2)
-      ## The general case with the for loop below would also work for
-      ## 2D but it's such a simple case we have it like this, no need
-      ## to make it hard to read.
-      conn = [0 1 0
-              1 1 1
-              0 1 0];
-    else
-      conn   = zeros (repmat (3, 1, num_dims));
-      template_idx = repmat ({2}, [num_dims 1]);
-      for dim = 1:num_dims
-        idx = template_idx;
-        idx(dim) = ":";
-        conn(idx{:}) = 1;
-      endfor
-    endif
-
-  elseif (strcmpi (conntype, "maximal"))
-    if (num_dims == 1)
-      ## This case does not exist in Matlab
-      conn = [1; 1; 1];
-    else
-      conn = ones (repmat (3, 1, num_dims));
-    endif
-
-  else
-    error ("conndef: invalid type of connectivity '%s'.", conntype);
-  endif
-
-endfunction
-
-%!demo
-%! ## Create a 2-D minimal connectivity array
-%! conndef (2, "minimal")
-
-%!assert (conndef (1, "minimal"), [1; 1; 1]);
-%!assert (conndef (2, "minimal"), [0 1 0; 1 1 1; 0 1 0]);
-
-%!test
-%! C = zeros (3, 3, 3);
-%! C(:,2,2) = 1;
-%! C(2,:,2) = 1;
-%! C(2,2,:) = 1;
-%! assert (conndef (3, "minimal"), C);
-
-%!test
-%! C = zeros (3, 3, 3, 3);
-%! C(:,:,2,1) = [0   0   0
-%!               0   1   0
-%!               0   0   0];
-%! C(:,:,1,2) = [0   0   0
-%!               0   1   0
-%!               0   0   0];
-%! C(:,:,2,2) = [0   1   0
-%!               1   1   1
-%!               0   1   0];
-%! C(:,:,3,2) = [0   0   0
-%!               0   1   0
-%!               0   0   0];
-%! C(:,:,2,3) = [0   0   0
-%!               0   1   0
-%!               0   0   0];
-%! assert (conndef (4, "minimal"), C);
-
-%!assert (conndef (1, "maximal"), ones (3, 1));
-%!assert (conndef (2, "maximal"), ones (3, 3));
-%!assert (conndef (3, "maximal"), ones (3, 3, 3));
-%!assert (conndef (4, "maximal"), ones (3, 3, 3, 3));
-
-%!error conndef (-2, "minimal")
-%!error conndef (char (2), "minimal")
-%!error <type of connectivity> conndef (3, "invalid")
-%!error conndef ("minimal", 3)
-
--- a/src/Makefile
+++ b/src/Makefile
@@ -2,7 +2,8 @@
 
 all: __spatial_filtering__.oct __bilateral__.oct __custom_gaussian_smoothing__.oct \
 	__boundary__.oct bwfill.oct rotate_scale.oct hough_line.oct \
-	graycomatrix.oct bwdist.oct nonmax_supress.oct bwlabeln.oct imerode.oct
+	graycomatrix.oct bwdist.oct nonmax_supress.oct bwlabeln.oct imerode.oct \
+	conndef.oct
 
 %.oct: %.cc
 	$(MKOCTFILE) $<
@@ -13,5 +14,12 @@
 imerode.oct: imerode.cc strel.cc
 	$(MKOCTFILE) $^ -o $@
 
+conndef.o: conndef.cc conndef.h
+	$(MKOCTFILE) $<
+
+conndef.oct: conndef.o
+	$(MKOCTFILE) $^
+
 clean:
 	rm -f *.o octave-core core *.oct *~
+
new file mode 100644
--- /dev/null
+++ b/src/conndef.cc
@@ -0,0 +1,258 @@
+// Copyright (C) 2014 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 Foundation; either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program 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 this program; if not, see
+// <http://www.gnu.org/licenses/>.
+
+#include <octave/oct.h>
+#include "conndef.h"
+
+using namespace octave::image;
+
+connectivity::connectivity ()
+{
+}
+
+connectivity::connectivity (const octave_idx_type& conn)
+{
+  if (conn == 4)
+    {
+      mask = boolNDArray (dim_vector (3, 3), true);
+      bool* md = mask.fortran_vec ();
+      md[ 0] = false;
+      md[ 2] = false;
+      md[ 6] = false;
+      md[ 8] = false;
+    }
+  else if (conn == 6)
+    {
+      mask = boolNDArray (dim_vector (3, 3, 3), false);
+      bool* md = mask.fortran_vec ();
+      md[ 4] = true;
+      md[10] = true;
+      md[12] = true;
+      md[13] = true;
+      md[14] = true;
+      md[16] = true;
+      md[22] = true;
+    }
+  else if (conn == 8)
+      mask = boolNDArray (dim_vector (3, 3), true);
+  else if (conn == 18)
+    {
+      mask = boolNDArray (dim_vector (3, 3, 3), true);
+      bool* md = mask.fortran_vec ();
+      md[ 0] = false;
+      md[ 2] = false;
+      md[ 6] = false;
+      md[ 8] = false;
+      md[18] = false;
+      md[20] = false;
+      md[24] = false;
+      md[26] = false;
+    }
+  else if (conn == 26)
+    mask = boolNDArray (dim_vector (3, 3, 3), true);
+  else
+    error ("conndef: invalid CONN `%i'", conn);
+
+  return;
+}
+
+
+connectivity::connectivity (const octave_idx_type& ndims,
+                            const std::string& type)
+{
+  dim_vector size;
+  if (ndims == 1)
+    size = dim_vector (3, 1);
+  else
+    size = dim_vector (3, 3);
+    size.resize (ndims, 3);
+
+  if (type == "maximal")
+    mask = boolNDArray (size, true);
+  else if (type == "minimal")
+    {
+      mask = boolNDArray (size, false);
+      bool* md = mask.fortran_vec ();
+
+      const octave_idx_type center = ceil (pow (3, ndims) /2);
+      md += (center -1);
+      md[0] = true;
+
+      for (octave_idx_type dim = 0; dim < ndims; dim++)
+        {
+          const octave_idx_type stride = pow (3, dim);
+          md[ stride] = true;
+          md[-stride] = true;
+        }
+    }
+  else
+    error ("conndef: invalid TYPE of connectivity '%s'", type.c_str ());
+
+  return;
+}
+
+
+// The conndef() function is really really simple and could have easily
+// been a m file (actually it once was, check the hg log if it ever needs
+// to be recovered) but then it would be awkward to call it from oct
+// functions so we made a C++ class for it.
+
+DEFUN_DLD(conndef, args, , "\
+-*- texinfo -*-\n\
+@deftypefn  {Function File} {} conndef (@var{conn})\n\
+@deftypefnx {Function File} {} conndef (@var{ndims}, @var{type})\n\
+Create connectivity array.\n\
+\n\
+Creates a matrix of for morphological operations, where elements with\n\
+a value of 1 are considered connected to the center element (a\n\
+connectivity array).\n\
+\n\
+It can be specified by the number of dimensions, @var{ndims}, and\n\
+@var{type} which must be one of the following strings:\n\
+\n\
+@table @asis\n\
+@item @qcode{\"minimal\"}\n\
+Neighbours touch the central element on a (@var{ndims}-1)-dimensional\n\
+surface.\n\
+\n\
+@item @qcode{\"maximal\"}\n\
+Neighbours touch the central element in any way. Equivalent to\n\
+@code{ones (repmat (3, 1, @var{ndims}))}.\n\
+\n\
+@end table\n\
+\n\
+or the number of connected elements to the center element, @var{conn},\n\
+in which case the following are valid:\n\
+\n\
+@table @asis\n\
+@item 4\n\
+Two-dimensional 4-connected neighborhood.\n\
+\n\
+@item 8\n\
+Two-dimensional 8-connected neighborhood.\n\
+\n\
+@item 6\n\
+Three-dimensional 6-connected neighborhood.\n\
+\n\
+@item 18\n\
+Three-dimensional 18-connected neighborhood.\n\
+\n\
+@item 26\n\
+Three-dimensional 26-connected neighborhood.\n\
+\n\
+@end table\n\
+\n\
+\n\
+@seealso{iptcheckconn, strel}\n\
+@end deftypefn")
+{
+  const octave_idx_type nargin = args.length ();
+
+  if (nargin < 1 || nargin > 2)
+    {
+      print_usage ();
+      return octave_value ();
+    }
+  const octave_idx_type arg0 = args(0).idx_type_value (true);
+  if (error_state || arg0 < 1)
+    {
+      error ("conndef: NDIMS and CONN must be a positive integer");
+      return octave_value ();
+    }
+
+  connectivity conn;
+  if (nargin == 1)
+    conn = connectivity (arg0);
+  else
+    {
+      const std::string type = args(1).string_value ();
+      if (error_state)
+        {
+          error ("conndef: TYPE must be a string");
+          return octave_value ();
+        }
+      conn = connectivity (arg0, type);
+    }
+
+  // we must return an array of class double
+  return octave_value (NDArray (conn.mask));
+}
+
+
+/*
+%!assert (conndef (1, "minimal"), [1; 1; 1]);
+%!assert (conndef (2, "minimal"), [0 1 0; 1 1 1; 0 1 0]);
+
+%!test
+%! C = zeros (3, 3, 3);
+%! C(:,2,2) = 1;
+%! C(2,:,2) = 1;
+%! C(2,2,:) = 1;
+%! assert (conndef (3, "minimal"), C);
+
+%!test
+%! C = zeros (3, 3, 3, 3);
+%! C(:,:,2,1) = [0   0   0
+%!               0   1   0
+%!               0   0   0];
+%! C(:,:,1,2) = [0   0   0
+%!               0   1   0
+%!               0   0   0];
+%! C(:,:,2,2) = [0   1   0
+%!               1   1   1
+%!               0   1   0];
+%! C(:,:,3,2) = [0   0   0
+%!               0   1   0
+%!               0   0   0];
+%! C(:,:,2,3) = [0   0   0
+%!               0   1   0
+%!               0   0   0];
+%! assert (conndef (4, "minimal"), C);
+
+%!assert (conndef (1, "maximal"), ones (3, 1));
+%!assert (conndef (2, "maximal"), ones (3, 3));
+%!assert (conndef (3, "maximal"), ones (3, 3, 3));
+%!assert (conndef (4, "maximal"), ones (3, 3, 3, 3));
+
+%!assert (nnz (conndef (3, "minimal")), 7)
+%!assert (nnz (conndef (4, "minimal")), 9)
+%!assert (nnz (conndef (5, "minimal")), 11)
+%!assert (nnz (conndef (6, "minimal")), 13)
+
+%!assert (find (conndef (3, "minimal")), [5 11 13 14 15 17 23](:))
+%!assert (find (conndef (4, "minimal")), [14 32 38 40 41 42 44 50 68](:))
+%!assert (find (conndef (5, "minimal")),
+%!        [   41   95  113  119  121  122  123  125  131  149  203](:))
+%!assert (find (conndef (6, "minimal")),
+%!        [  122  284  338  356  362  364  365  366  368  374  392  446  608](:))
+
+%!error conndef ()
+%!error conndef (-2, "minimal")
+%!error conndef (char (2), "minimal")
+%!error <TYPE of connectivity> conndef (3, "invalid")
+%!error conndef ("minimal", 3)
+%!error <invalid CONN> conndef (10)
+
+%!assert (conndef (2, "minimal"), conndef (4))
+%!assert (conndef (2, "maximal"), conndef (8))
+%!assert (conndef (3, "minimal"), conndef (6))
+%!assert (conndef (3, "maximal"), conndef (26))
+
+%!assert (conndef (18), reshape ([0 1 0 1 1 1 0 1 0
+%!                                1 1 1 1 1 1 1 1 1
+%!                                0 1 0 1 1 1 0 1 0], [3 3 3]))
+
+*/
new file mode 100644
--- /dev/null
+++ b/src/conndef.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2014 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 Foundation; either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program 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 this program; if not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef OCTAVE_IMAGE_CONNDEF
+#define OCTAVE_IMAGE_CONNDEF
+
+#include <octave/oct.h>
+
+namespace octave
+{
+  namespace image
+  {
+    class connectivity
+    {
+      public:
+        connectivity ();
+        connectivity (const octave_idx_type& conn);
+        connectivity (const octave_idx_type& ndims, const std::string& type);
+
+        boolNDArray mask;
+    };
+  }
+}
+
+#endif