Logo Search packages:      
Sourcecode: octave-image version File versions  Download package

bwfill.cc

/*
 * BWFILL: fill a bw image starting at points
 * imo= block(im, xregs, yregs);
 *
 * Copyright (C) 1999 Andy Adler
 * This code has no warrany whatsoever.
 * Do what you like with this code as long as you
 *     leave this copyright in place.
 *
 * $Id: bwfill.cc 5588 2009-03-07 18:39:05Z hauberg $
 */

#include <octave/oct.h>

#define   ptUP     (-1)
#define   ptDN     (+1)
#define   ptRT     (+ioM)
#define   ptLF     (-ioM)

/*
 * check if the point needs to be filled, if so
 * fill it and change the appropriate variables
 */
void checkpoint (int pt, unsigned char *imo, int *ptstack, int *npoints)
{
// printf("filling %d np=%d fill=%d\n",pt,*npoints, *(imo+pt)==0 );
  if (*(imo+pt) != 0) return;

  *(imo+pt) = 2;
  *(ptstack + (*npoints))= pt;
  (*npoints)++;
}

DEFUN_DLD (bwfill, args, ,"\
-*- texinfo -*-\n\
@deftypefn {Function File} {[@var{bw2}, @var{idx}] =} bwfill(@var{bw1}, @var{c}, @var{r}, @var{n})\n\
Perform a flood-fill operation on the binary image @var{bw1}.\n\
The flood-filling starts in the pixel (@var{r}, @var{c}). If @var{r} and @var{c}\n\
are vectors of the same length, each pixel pair (@var{r}(i), @var{c}(i)) will\n\
be a starting point for a flood-fill operation.\n\
The argument @var{n} changes the neighborhood connectivity for the flood-fill\n\
operation. @var{n} can be either 4 or 8, and has a default value of 8.\n\
\n\
The output is the processed image @var{bw2} and the indexes of the filled\n\
pixels @var{idx}\n\
@deftypefnx{Function File} {[@var{bw2}, @var{idx}] =} bwfill(@var{bw1}, \"holes\", @var{n})\n\
If the string \"holes\" is given instead of starting points for the flood-fill\n\
operation, the function finds interior holes in @var{bw1} and fills them.\n\
@end deftypefn\n\
")
{
  octave_value_list retval;
  octave_value tmp;
  ColumnVector xseed, yseed ;
  const int nargin = args.length ();

  if (nargin < 2 )
    {
      print_usage ();
      return retval;
    }

   const Matrix im = args (0).matrix_value ();
   if (error_state)
     {
       error ("bwfill: first input argument must be a matrix");
       return retval;
     }
     
  const int imM = im.rows ();
  const int imN = im.columns ();

  int nb = 8;
  int npoints = 0;
  bool fillmode= false;
  if (args (1).is_string () && args (1).string_value () == "holes")
    {
      fillmode= true;

      npoints= 2 * (imM + imN - 4); // don't start fill from corners

      xseed = ColumnVector (npoints);
      yseed = ColumnVector (npoints);
      int idx= 0;
      for (int j=2; j<= imN-1; j++)
        {
          xseed (idx)   = j;
          yseed (idx++) = 1;   
          xseed (idx)   = j;
          yseed (idx++) = imM;   
        }

      for (int i=2; i<= imM-1; i++)
        {
          yseed (idx)   = i;
          xseed (idx++) = 1;   
          yseed (idx)   = i;
          xseed (idx++) = imN;   
        }

      if (nargin >= 4)
         nb = (int)args (2).double_value ();
     }
  else // end: holes mode?
    {
      {
        ColumnVector tmp (args (1).vector_value ());
        if (error_state)
          {
            error ("bwfill: second input argument must be a string");
            return retval;
          }
        xseed = tmp;
      }
      {
        ColumnVector tmp (args (2).vector_value ());
        if (error_state)
          {
            error ("bwfill: third input argument must be a string");
            return retval;
          }
       yseed = tmp;
      }
      npoints= xseed.length ();
      if (nargin >= 4) 
        nb = (int)args (3).double_value ();
  } // holes mode? 

/*
 * put a one pixel thick boundary around the image
 *  so that we can be more efficient in the main loop
 */
  int ioM = imM + 2;
  OCTAVE_LOCAL_BUFFER (unsigned char, imo, (imM+2) * (imN+2));

  for (int i = 0; i < imM; i++) 
    for (int j = 0; j < imN; j++)
      imo [(i+1) + ioM*(j+1)] = (im (i, j) > 0);

  for (int i = 0; i < ioM; i++)
    imo [i]= imo [i + ioM*(imN+1)] = 3;

  for (int j = 1; j < imN+1; j++)
    imo [ioM*j]= imo[imM+1 + ioM*j] = 3;

  // This is obviously big enough for the point stack, but I'm
  // sure it can be smaller. 
  OCTAVE_LOCAL_BUFFER (int, ptstack, ioM*imN);

  int seedidx = npoints; 
  npoints= 0;
  while ( (--seedidx) >= 0 )
    {
      // no need to add 1 to convert indexing style because we're adding a boundary
      const int x = xseed (seedidx);
      const int y = yseed (seedidx);
      if (x < 1 || y < 1 || x > imN || y > imM)
        {
          warning ("bwfill: (%d, %d) out of bounds", x, y);
          continue;
        }
      const int pt = x * ioM + y; 
      checkpoint (pt , imo, ptstack, &npoints);
    }

  while (npoints > 0)
    {
      npoints--;
      int pt = ptstack [npoints];
      
      checkpoint (pt + ptLF, imo, ptstack, &npoints);
      checkpoint (pt + ptRT, imo, ptstack, &npoints);
      checkpoint (pt + ptUP, imo, ptstack, &npoints);
      checkpoint (pt + ptDN, imo, ptstack, &npoints);
      
      if (nb==8)
        {
          checkpoint (pt + ptLF + ptUP, imo, ptstack, &npoints);
          checkpoint (pt + ptRT + ptUP, imo, ptstack, &npoints);
          checkpoint (pt + ptLF + ptDN, imo, ptstack, &npoints);
          checkpoint (pt + ptRT + ptDN, imo, ptstack, &npoints);
        }
    } // while ( npoints > 0)

  Matrix imout (imM, imN);
  ColumnVector idxout (imM*imN);
  int idx = 0;

  int notvalidpt = 0;
  int idxpoint = 2;
  if (fillmode)
    {
      notvalidpt = 2;
      idxpoint   = 0;
    }

  for (int i = 0; i < imM; i++) 
    for (int j = 0; j < imN; j++)
      {
        imout (i, j) = (double) (imo [(i+1) + ioM*(j+1)] != notvalidpt);
        if (imo [(i+1) + ioM*(j+1)] == idxpoint)
          idxout (idx++) = (double) (i + j*imM + 1);
      }

  /*
  Matrix imout( imM+2, imN+2 );
  for (int i=0; i<imM+2; i++) 
    for (int j=0; j<imN+2; j++)
      imout(i,j) = (double) imo[i + ioM*j];
  */

  retval (0)= imout;
  // we need to do this to be able to return a proper empty vector
  if (idx > 0) 
    retval (1)= idxout.extract (0, idx-1);
  else
    retval (1)= ColumnVector (0);
  return retval;
}


/*
 * $Log$
 * Revision 1.3  2007/01/04 21:58:50  hauberg
 * Texinfo-fication of the help texts
 *
 * Revision 1.2  2006/08/23 23:58:45  adb014
 * remove cruft of #ifdef
 *
 * Revision 1.1  2006/08/20 12:59:36  hauberg
 * Changed the structure to match the package system
 *
 * Revision 1.7  2006/05/19 06:58:50  jwe
 * *** empty log message ***
 *
 * Revision 1.5  2003/05/15 21:25:40  pkienzle
 * OCTAVE_LOCAL_BUFFER now requires #include <memory>
 *
 * Revision 1.4  2003/03/05 15:31:52  pkienzle
 * Backport to octave-2.1.36
 *
 * Revision 1.3  2003/02/20 23:03:57  pkienzle
 * Use of "T x[n]" where n is not constant is a g++ extension so replace it with
 * OCTAVE_LOCAL_BUFFER(T,x,n), and other things to keep the picky MipsPRO CC
 * compiler happy.
 *
 * Revision 1.2  2002/11/02 10:39:36  pkienzle
 * gcc 3.2 wants \n\ for multi-line strings.
 *
 * Revision 1.1  2002/03/17 02:38:51  aadler
 * fill and edge detection operators
 *
 * Revision 1.9  2000/06/16 20:22:47  aadler
 * mods for 2.1/2.0 compat
 *
 * Revision 1.8  2000/06/13 17:27:24  aadler
 * mods for 2.1.30
 *
 * Revision 1.7  1999/06/10 19:42:12  aadler
 * minor verbose fix
 *
 * Revision 1.6  1999/06/08 16:30:30  aadler
 * bug fix. reversed r,c input arguments
 *
 * Revision 1.5  1999/06/08 15:41:02  aadler
 * now fills in holes
 *
 * Revision 1.4  1999/06/08 15:21:02  aadler
 * fixed bug that so specified points are only used if they can fill
 *
 * Revision 1.3  1999/06/08 15:05:08  aadler
 * now returns 1 and gives index output
 *
 * Revision 1.2  1999/06/04 21:58:57  aadler
 * fixed 8 vs 4 neighborhood
 *
 * Revision 1.1  1999/06/04 21:43:20  aadler
 * Initial revision
 *
 *
 */

Generated by  Doxygen 1.6.0   Back to index