changeset 23:97f107d68d4f

for Jeff Boyd <boyd@cpsc.ucalgary.ca>: C++ version of bwlabel
author pkienzle
date Fri, 06 Sep 2002 19:32:57 +0000
parents e749d76cd428
children 569cef7db099
files Makefile bwlabel.cc
diffstat 2 files changed, 231 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
 	JPEG=jpgwrite.oct jpgread.oct
 endif
 
-all: conv2.oct cordflt2.oct $(JPEG)
+all: conv2.oct cordflt2.oct bwlabel.oct $(JPEG)
 
 jpgread.oct: jpgread.cc
 	$(MKOCTFILE) $< -ljpeg
new file mode 100644
--- /dev/null
+++ b/bwlabel.cc
@@ -0,0 +1,230 @@
+/* ---------------------------------------------------------------------
+
+    bwimage.cc - octave module to label componenets of a binary image
+
+    copyright 2002 Jeffrey E. Boyd
+
+    - uses 4, 6, or 8 connectedness
+    - See BKP Horn, Robot Vision, MIT Press, 1986, p 66 - 71 
+
+    labeling scheme
+
+        +-+-+-+
+        |D|C|E|
+        +-+-+-+
+        |B|A| |
+        +-+-+-+
+        | | | |
+        +-+-+-+
+                
+    A is the center pixel of a neighborhood.  In the 3 versions of
+    connectedness:
+    
+    4:  A connects to B and C
+    6:  A connects to B, C, and D
+    8:  A connects to B, C, D, and E
+    
+    
+--------------------------------------------------------------------- */
+
+
+
+#include <oct.h>
+#include <stdio.h>
+
+
+#define     NO_OBJECT       0
+#define     MIN(x, y)       (((x) < (y)) ? (x) : (y))
+
+
+
+static int find( int *, int );
+
+static bool any_bad_argument( const octave_value_list& );
+
+
+
+DEFUN_DLD( bwlabel, args, ,
+"\n\
+[l,num] = bwlabel( bw, n ) - label foreground components of boolean image\n\
+\n\
+    bw  -   boolean image array\n\
+    n   -   neighborhood connectedness (4, 6,or 8)\n\
+\n\
+    l   -   label image array\n\
+    num -   number of components labeled\n\
+\n\
+    The algorithm is derived from  BKP Horn, Robot Vision, MIT Press,\n\
+    1986, p 65 - 89 \n" )
+{
+    if ( any_bad_argument(args) )
+        return octave_value_list();
+    
+    // input arguments
+    Matrix BW = args(0).matrix_value();     // the input binary image
+    int n;
+    if ( args.length() < 2 ) n = 6;         // n-hood connectivity
+    else n = args(1).int_value(); 
+    int nr = args(0).rows();
+    int nc = args(0).columns();
+    
+    // results
+    Matrix L( nr, nc );     // the label image
+    int nobj;                               // number of objects found in image
+    
+    // other variables
+    int lset[nr * nc];   // label table/tree
+    int ntable;                             // number of elements in the component table/tree
+    
+    ntable = 0;
+    lset[0] = 0;
+    
+    for( int r = 0; r < nr; r++ ) {
+        for( int c = 0; c < nc; c++ ) {            
+            if ( BW.elem(r,c) ) {               // if A is an object
+                // get the neighboring pixels B, C, D, and E
+                int B, C, D, E;
+                if ( c == 0 ) B = 0; else B = find( lset, (int)L.elem(r,c-1) );
+                if ( r == 0 ) C = 0; else C = find( lset, (int)L.elem(r-1,c) );
+                if ( r == 0 || c == 0 ) D = 0; else D = find( lset, (int)L.elem(r-1,c-1) );
+                if ( r == 0 || c == nc - 1 ) E = 0;
+                    else E = find( lset, (int)L.elem(r-1,c+1) );
+                    
+                if ( n == 4 ) {
+                    // apply 4 connectedness
+                    if ( B && C ) {        // B and C are labeled
+                        if ( B == C )
+                            L.elem(r,c) = B;
+                        else {
+                            lset[C] = B;
+                            L.elem(r,c) = B;
+                        }
+                    } else if ( B )             // B is object but C is not
+                        L.elem(r,c) = B;
+                    else if ( C )               // C is object but B is not
+                        L.elem(r,c) = C;
+                    else {                      // B, C, D not object - new object
+                        //   label and put into table
+                        ntable++;
+                        L.elem(r,c) = lset[ ntable ] = ntable;
+                    }
+                } else if ( n == 6 ) {
+                    // apply 6 connected ness
+                    if ( D )                    // D object, copy label and move on
+                        L.elem(r,c) = D;
+                    else if ( B && C ) {        // B and C are labeled
+                        if ( B == C )
+                            L.elem(r,c) = B;
+                        else {
+                            int tlabel = MIN(B,C);
+                            lset[B] = tlabel;
+                            lset[C] = tlabel;
+                            L.elem(r,c) = tlabel;
+                        }
+                    } else if ( B )             // B is object but C is not
+                        L.elem(r,c) = B;
+                    else if ( C )               // C is object but B is not
+                        L.elem(r,c) = C;
+                    else {                      // B, C, D not object - new object
+                        //   label and put into table
+                        ntable++;
+                        L.elem(r,c) = lset[ ntable ] = ntable;
+                    }
+                } else if ( n == 8 ) {
+                    // apply 8 connectedness
+                    if ( B || C || D || E ) {
+                        int tlabel = B;
+                        if ( B ) tlabel = B;
+                        else if ( C ) tlabel = C;
+                        else if ( D ) tlabel = D;
+                        else if ( E ) tlabel = E;
+                        L.elem(r,c) = tlabel;
+                        if ( B && B != tlabel ) lset[B] = tlabel;
+                        if ( C && C != tlabel ) lset[C] = tlabel;
+                        if ( D && D != tlabel ) lset[D] = tlabel;
+                        if ( E && E != tlabel ) lset[E] = tlabel;
+                    } else {
+                        //   label and put into table
+                        ntable++;
+                        L.elem(r,c) = lset[ ntable ] = ntable;
+                    }
+                }
+            } else {
+                L.elem(r,c) = NO_OBJECT;      // A is not an object so leave it
+            }
+        }
+    }
+    
+    // consolidate component table
+    for( int i = 0; i <= ntable; i++ )
+        lset[i] = find( lset, i );
+
+    // run image through the look-up table
+    for( int r = 0; r < nr; r++ )
+        for( int c = 0; c < nc; c++ )
+            L.elem(r,c) = lset[ (int)L.elem(r,c) ];
+    
+    // count up the objects in the image
+    for( int i = 0; i <= ntable; i++ )
+        lset[i] = 0;
+
+    for( int r = 0; r < nr; r++ )
+        for( int c = 0; c < nc; c++ )
+            lset[ (int)L.elem(r,c) ]++;
+
+    // number the objects from 1 through n objects
+    nobj = 0;
+    lset[0] = 0;
+    for( int i = 1; i <= ntable; i++ )
+        if ( lset[i] > 0 )
+            lset[i] = ++nobj;
+
+    // run through the look-up table again
+    for( int r = 0; r < nr; r++ )
+        for( int c = 0; c < nc; c++ )
+            L.elem(r,c) = lset[ (int)L.elem(r,c) ];
+
+    octave_value_list rval;
+    rval(0) = L;
+    rval(1) = (double)nobj;
+    return rval;
+}
+
+
+static bool any_bad_argument( const octave_value_list& args )
+{
+    if ( args.length() < 1 || args.length() > 2 ) {
+        error( "bwlabel: number of arguments - expecting bwlabel(bw) or bwlabel(bw,n)" );
+        return true;
+    }
+    
+    if ( !args(0).is_matrix_type() ) {
+        error( "bwlabel: matrix expected for first argument" );
+        return true;
+    }
+    
+    if ( args.length() == 2 ) {
+        if ( !args(1).is_real_scalar() ) {
+            error( "bwlabel: expecting real scalar for second argument" );
+            return true;
+        }
+        int n = args(1).int_value();
+        if ( n != 4 && n != 6 && n != 8 ) {
+            error( "bwlabel: in bwlabel(BW,n) n must be in {4,6,8}" );
+            return true;
+        }
+    }
+    
+    return false;
+    
+}
+
+
+static int find( int set[], int x )
+{
+    int r = x;
+    while ( set[r] != r )
+        r = set[r];
+    return r;
+}
+