# HG changeset patch # User Carnë Draug # Date 1412191357 -3600 # Node ID a2140b980079cf889cb6294fe15b61c37352703a # Parent a65390dffc5ad8a7664eaef64b0aa2fd41d9b79b iptcheckconn: implement in C++ as static method for connectivity. * iptcheckconn.m: file removed; help text and tests reused for C++. * conndef.cc: implement two new connectivity::validate() methods and the iptcheckconn function for Octave as caller to those methods. * conndef.h: define the connectivity::validate() static methods. * COPYING diff --git a/COPYING b/COPYING --- a/COPYING +++ b/COPYING @@ -97,7 +97,6 @@ inst/imtransform.m GPLv3+ inst/imtranslate.m GPLv3+ inst/intlut.m GPLv3+ -inst/iptcheckconn.m GPLv3+ inst/iptcheckmap.m GPLv3+ inst/iptchecknargin.m GPLv3+ inst/iptcheckstrs.m GPLv3+ diff --git a/inst/iptcheckconn.m b/inst/iptcheckconn.m deleted file mode 100644 --- a/inst/iptcheckconn.m +++ /dev/null @@ -1,81 +0,0 @@ -## Copyright (C) 2011 Carnë Draug -## -## 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 . - -## -*- texinfo -*- -## @deftypefn {Function File} {} iptcheckconn (@var{con}, @var{func_name}, @var{var_name}, @var{pos}) -## Check if argument is valid connectivity. -## -## If @var{con} is not a valid connectivity argument, gives a properly formatted -## error message. @var{func_name} is the name of the function to be used on the -## error message, @var{var_name} the name of the argument being checked (for the -## error message), and @var{pos} the position of the argument in the input. -## -## A valid connectivity argument must be either double or logical. It must also -## be either a scalar from set [1 4 6 8 18 26], or a symmetric matrix with all -## dimensions of size 3, with only 0 or 1 as values, and 1 at its center. -## -## @end deftypefn - -function iptcheckconn (con, func_name, var_name, pos) - - ## thanks to Oldak in ##matlab for checking the validity of connectivities - ## with more than 2D and the error messages - - if (nargin != 4) - print_usage; - elseif (!ischar (func_name)) - error ("Argument func_name must be a string"); - elseif (!ischar (var_name)) - error ("Argument var_name must be a string"); - elseif (!isnumeric (pos) || !isscalar (pos) || !isreal (pos) || pos <= 0 || rem (pos, 1) != 0) - error ("Argument pos must be a real positive integer"); - endif - - base_msg = sprintf ("Function %s expected input number %d, %s, to be a valid connectivity specifier.\n ", ... - func_name, pos, var_name); - - ## error ends in \n so the back trace of the error is not show. This is on - ## purpose since the whole idea of this function is already to give a properly - ## formatted error message - if (! any (strcmp (class (con), {'logical', 'double'})) || ! isreal (con)) - error ("%sConnectivity must be a real number of the logical or double class.\n", base_msg); - elseif (isscalar (con)) - if (!any (con == [1 4 6 8 18 26])) - error ("%sIf connectivity is a scalar, must belong to the set [1 4 6 8 18 26].\n", base_msg); - endif - elseif (ismatrix (con)) - center_index = ceil(numel(con)/2); - if (any (size (con) != 3)) - error ("%sIf connectivity is a matrix, all dimensions must have size 3.\n", base_msg); - elseif (!all (con(:) == 1 | con(:) == 0)) - error ("%sIf connectivity is a matrix, only 0 and 1 are valid.\n", base_msg); - elseif (con(center_index) != 1) - error ("%sIf connectivity is a matrix, central element must be 1.\n", base_msg); - elseif (!all (con(1:center_index-1) == con(end:-1:center_index+1))) - error ("%sIf connectivity is a matrix, it must be symmetric relative to its center.\n", base_msg); - endif - else - error ("%s\n", base_msg); - endif - -endfunction - -%!test ("iptcheckconn (4, 'func', 'var', 2)"); # simple must work -%!test ("iptcheckconn (ones(3,3,3,3), 'func', 'var', 2)"); # accept more than just 3D -%!fail ("iptcheckconn (3, 'func', 'var', 2)"); # does not belong to set -%!fail ("iptcheckconn ([1 1 1; 1 0 1; 1 1 1], 'func', 'var', 2)"); # matrix center must be 1 -%!fail ("iptcheckconn ([1 2 1; 1 1 1; 1 1 1], 'func', 'var', 2)"); # matrix must be 1 and 0 only -%!fail ("iptcheckconn ([0 1 1; 1 1 1; 1 1 1], 'func', 'var', 2)"); # matrix must be symmetric -%!fail ("iptcheckconn (ones(3,3,3,4), 'func', 'var', 2)"); # matrix must have all sizes 3 diff --git a/src/conndef.cc b/src/conndef.cc --- a/src/conndef.cc +++ b/src/conndef.cc @@ -89,7 +89,7 @@ mask = boolNDArray (size, false); bool* md = mask.fortran_vec (); - md += int (ceil (pow (3, ndims) /2) -1); // move to center + md += int (floor (pow (3, ndims) /2)); // move to center md[0] = true; for (octave_idx_type dim = 0; dim < ndims; dim++) { @@ -124,7 +124,7 @@ if (mask(ind)) { for (octave_idx_type i = 0; i < ndims; i++) - diff(i) = 1 - sub(i); + diff(i) = 1 - sub(i); // 1 is center since conn is 3x3x...x3 octave_idx_type off = diff(0); for (octave_idx_type dim = 1; dim < ndims; dim++) @@ -138,6 +138,44 @@ } +bool +connectivity::validate (const double& conn) +{ + if (conn == 4 || conn == 8 || conn == 6 || conn == 18 || conn == 26 + || conn == 1) + return true; + + return false; +} + + +bool +connectivity::validate (const boolNDArray& mask) +{ + // Must be 3x3x3x...x3 + const dim_vector dims = mask.dims (); + const octave_idx_type ndims = mask.ndims (); + for (octave_idx_type i = 0; i < ndims; i++) + if (dims(i) != 3) + return false; + + // Center must be true + const octave_idx_type numel = mask.numel (); + const octave_idx_type center = floor (numel /2); + if (! mask(center)) + return false; + + // Must be symmetric relative to its center + const bool* start = mask.fortran_vec (); + const bool* end = mask.fortran_vec () + (numel -1); + for (octave_idx_type i = 0; i < center; i++) + if (start[i] != end[-i]) + return false; + + return true; +} + + // 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 @@ -145,8 +183,8 @@ DEFUN_DLD(conndef, args, , "\ -*- texinfo -*-\n\ -@deftypefn {Function File} {} conndef (@var{conn})\n\ -@deftypefnx {Function File} {} conndef (@var{ndims}, @var{type})\n\ +@deftypefn {Loadable Function} {} conndef (@var{conn})\n\ +@deftypefnx {Loadable Function} {} conndef (@var{ndims}, @var{type})\n\ Create connectivity array.\n\ \n\ Creates a matrix of for morphological operations, where elements with\n\ @@ -289,3 +327,90 @@ %! 0 1 0 1 1 1 0 1 0], [3 3 3])) */ + +// PKG_ADD: autoload ("iptcheckconn", which ("conndef")); +// PKG_DEL: autoload ("iptcheckconn", which ("conndef"), "remove"); +DEFUN_DLD(iptcheckconn, args, , "\ +-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} iptcheckconn (@var{con}, @var{func}, @var{var}, @var{pos})\n\ +Check if argument is valid connectivity.\n\ +\n\ +If @var{conn} is not a valid connectivity argument, gives a properly\n\ +formatted error message. @var{func} is the name of the function to be\n\ +used on the error message, @var{var} the name of the argument being\n\ +checked (for the error message), and @var{pos} the position of the\n\ +argument in the input.\n\ +\n\ +A valid connectivity argument must be either double or logical. It must\n\ +also be either a scalar from set [1 4 6 8 18 26], or a symmetric matrix\n\ +with all dimensions of size 3, with only 0 or 1 as values, and 1 at its\n\ +center.\n\ +\n\ +@seealso{conndef}\n\ +@end deftypefn") +{ + const octave_idx_type nargin = args.length (); +// const octave_value rv = octave_value (); + + if (nargin != 4) + { + print_usage (); + return octave_value (); + } + + const std::string func = args(1).string_value (); + if (error_state) + { + error ("iptcheckconn: FUNC must be a string"); + return octave_value (); + } + const std::string var = args(2).string_value (); + if (error_state) + { + error ("iptcheckconn: VAR must be a string"); + return octave_value (); + } + const octave_idx_type pos = args(3).idx_type_value (true); + if (error_state || pos < 1) + { + error ("iptcheckconn: POS must be a positive integer"); + return octave_value (); + } + + bool bad = true; + + const double conn = args(0).double_value (); + // check is_scalar_type because of the warning Octave:array-to-scalar + if (! error_state && args(0).is_scalar_type () // + && connectivity::validate (conn)) + bad = false; + else + { + const boolNDArray mask = args(0).bool_array_value (); + // bool_array_value converts anything other than 0 to true, which will + // then validate asconn array, hence any_element_not_one_or_zero + if (! error_state && connectivity::validate (mask) + && ! args(0).array_value ().any_element_not_one_or_zero ()) + bad = false; + } + + if (bad) + error ("%s: %s at pos %i is not a valid connectivity array", + func.c_str (), var.c_str (), pos); + + return octave_value (); +} + +/* +// the complete error message should be "expected error <.> but got none", +// but how to escape <> within the error message? + +%!error fail ("iptcheckconn (4, 'func', 'var', 2)"); +%!error fail ("iptcheckconn (ones (3, 3, 3, 3), 'func', 'var', 2)"); + +%!error iptcheckconn (3, "func", "var", 2); +%!error iptcheckconn ([1 1 1; 1 0 1; 1 1 1], "func", "var", 2); +%!error iptcheckconn ([1 2 1; 1 1 1; 1 1 1], "func", "var", 2); +%!error iptcheckconn ([0 1 1; 1 1 1; 1 1 1], "func", "var", 2); +%!error iptcheckconn (ones (3, 3, 3, 4), "func", "var", 2); +*/ diff --git a/src/conndef.h b/src/conndef.h --- a/src/conndef.h +++ b/src/conndef.h @@ -35,6 +35,9 @@ // For a matrix of size `size', what are the offsets for all of its // connected elements (will have negative and positive values). Array offsets (const dim_vector& size) const; + + static bool validate (const boolNDArray& mask); + static bool validate (const double& conn); }; } }