view src/conndef.cc @ 906:475a5a2a08cb

Fix make rules and handling of "shared" libraries. * Makefile: we wanted to have shared libraries for strel.so and connectivity.so but that's not really possible (Octave's pkg does not have a system to handle this). So we create object files and statically link them. This the closest we can do at the moment. Also change setting CXXFLAGS to only add '-std=c++0x' rather than defining all the other options again. * conndef.h, connectivity.h: renamed the first as the later. * conndef.cc: moved the definition of the connectivity class into its own connectivity.cc file and include that. The idea is to then create a shared library without Fconndef and Fiptcheckconn but that did not reallt happen yet. * connectivity.cc: definition of the connectivity class, from conndef.cc. * bwlabeln.cc: change the include for the name connectivity header file. * COPYING: update license for the new files.
author Carnë Draug <carandraug@octave.org>
date Thu, 30 Oct 2014 21:34:55 +0000
parents f34897bc944f
children
line wrap: on
line source

// 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 "connectivity.h"
using namespace octave::image;

// 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  {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\
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)
    {
      try
        {conn = connectivity (arg0);}
      catch (invalid_connectivity& e)
        {
          error ("conndef: CONN %s", e.what ());
          return octave_value ();
        }
    }
  else
    {
      const std::string type = args(1).string_value ();
      if (error_state)
        {
          error ("conndef: TYPE must be a string");
          return octave_value ();
        }
      try
        {conn = connectivity (arg0, type);}
      catch (invalid_connectivity& e)
        {
          error ("conndef: TYPE %s", e.what ());
          return octave_value ();
        }
    }

  // 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 <must be a positive integer> conndef (-2, "minimal")
%!error conndef (char (2), "minimal")
%!error conndef ("minimal", 3)
%!error <TYPE must be "maximal" or "minimal"> conndef (3, "invalid")
%!error <CONN must be in the set> 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]))
*/

// PKG_ADD: autoload ("iptcheckconn", which ("conndef"));
// PKG_DEL: autoload ("iptcheckconn", which ("conndef"), "remove");
DEFUN_DLD(iptcheckconn, args, , "\
-*- texinfo -*-\n\
@deftypefn  {Loadable Function} {} iptcheckconn (@var{conn}, @var{func}, @var{var})\n\
@deftypefnx {Loadable Function} {} iptcheckconn (@var{conn}, @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 [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 ();

  if (nargin < 3 || 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 ();
    }
  octave_idx_type pos (0);
  if (nargin > 3)
    {
      pos = args(3).idx_type_value (true);
      if (error_state || pos < 1)
        {
          error ("iptcheckconn: POS must be a positive integer");
          return octave_value ();
        }
    }

  try
    {const connectivity conn (args(0));}
  catch (invalid_connectivity& e)
    {
      if (pos == 0)
        error ("%s: %s %s", func.c_str (), var.c_str (), e.what ());
      else
        error ("%s: %s, at pos %i, %s",
               func.c_str (), var.c_str (), pos, e.what ());
    }
  return octave_value ();
}

/*
// the complete error message should be "expected error <.> but got none",
// but how to escape <> within the error message?

%!error <expected error> fail ("iptcheckconn ( 4, 'func', 'var')");
%!error <expected error> fail ("iptcheckconn ( 6, 'func', 'var')");
%!error <expected error> fail ("iptcheckconn ( 8, 'func', 'var')");
%!error <expected error> fail ("iptcheckconn (18, 'func', 'var')");
%!error <expected error> fail ("iptcheckconn (26, 'func', 'var')");

%!error <expected error> fail ("iptcheckconn (1, 'func', 'var')");
%!error <expected error> fail ("iptcheckconn (ones (3, 1), 'func', 'var')");
%!error <expected error> fail ("iptcheckconn (ones (3, 3), 'func', 'var')");
%!error <expected error> fail ("iptcheckconn (ones (3, 3, 3), 'func', 'var')");
%!error <expected error> fail ("iptcheckconn (ones (3, 3, 3, 3), 'func', 'var')");

%!error <VAR must be logical or in> iptcheckconn (3, "func", "VAR");
%!error <VAR center is not true> iptcheckconn ([1 1 1; 1 0 1; 1 1 1], "func", "VAR");
%!error <VAR must be logical or in> iptcheckconn ([1 2 1; 1 1 1; 1 1 1], "func", "VAR");
%!error <VAR is not symmetric relative to its center> iptcheckconn ([0 1 1; 1 1 1; 1 1 1], "func", "VAR");
%!error <VAR is not 3x3x...x3> iptcheckconn (ones (3, 3, 3, 4), "func", "VAR");
*/