From: <car...@us...> - 2011-11-28 19:13:45
|
Revision: 9212 http://octave.svn.sourceforge.net/octave/?rev=9212&view=rev Author: carandraug Date: 2011-11-28 19:13:38 +0000 (Mon, 28 Nov 2011) Log Message: ----------- bwlabeln: improved help text Modified Paths: -------------- trunk/octave-forge/main/image/src/bwlabeln.cc Modified: trunk/octave-forge/main/image/src/bwlabeln.cc =================================================================== --- trunk/octave-forge/main/image/src/bwlabeln.cc 2011-11-28 19:12:43 UTC (rev 9211) +++ trunk/octave-forge/main/image/src/bwlabeln.cc 2011-11-28 19:13:38 UTC (rev 9212) @@ -215,13 +215,16 @@ DEFUN_DLD(bwlabeln, args, , "\ -*- texinfo -*-\n\ @deftypefn {Function File} {[@var{l}, @var{num}] =} bwlabeln(@var{bw}, @var{n})\n\ +Label foreground objects in the n-dimensional binary image @var{bw}.\n\ \n\ -Labels foreground objects in the n-dimensional binary image @var{bw}.\n\ +The optional argument @var{n} sets the connectivity and defaults 26.\n\ +\n\ The output @var{l} is an Nd-array where 0 indicates a background\n\ pixel, 1 indicates that the pixel belong to object number 1, 2 that\n\ the pixel belong to object number 2, etc. The total number of objects\n\ is @var{num}.\n\ \n\ +@seealso{bwconncomp, bwlabel, regionprops}\n\ @end deftypefn\n\ ") { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jo...@us...> - 2012-09-04 01:58:12
|
Revision: 10958 http://octave.svn.sourceforge.net/octave/?rev=10958&view=rev Author: jordigh Date: 2012-09-04 01:58:03 +0000 (Tue, 04 Sep 2012) Log Message: ----------- Fix bwlabeln's input-checking, some futile attempts to optimise Modified Paths: -------------- trunk/octave-forge/main/image/src/bwlabeln.cc Modified: trunk/octave-forge/main/image/src/bwlabeln.cc =================================================================== --- trunk/octave-forge/main/image/src/bwlabeln.cc 2012-09-03 20:33:01 UTC (rev 10957) +++ trunk/octave-forge/main/image/src/bwlabeln.cc 2012-09-04 01:58:03 UTC (rev 10958) @@ -19,9 +19,6 @@ #include <set> #include "union-find.h++" - -dim_vector conn26_dim(3,3,3); -boolNDArray conn26(conn26_dim,1); typedef Array<octave_idx_type> coord; bool operator== (const coord& a, const coord& b) @@ -83,8 +80,6 @@ } }; -namespace { - // A few basic utility functions //{ inline @@ -135,7 +130,7 @@ operator- (const coord& a) { octave_idx_type na = a.nelem (); - coord retval( dim_vector(na,1) ); + coord retval (dim_vector(na,1) ); for (octave_idx_type i = 0; i < na; i++) { retval(i) = -a(i); @@ -144,52 +139,10 @@ } //} -bool any_bad_argument (const octave_value_list& args) -{ - return false; - - const int nargin = args.length (); - if (nargin < 1 || nargin > 2) - { - print_usage (); - return true; - } - - if (!args (0).is_bool_type ()) - { - error ("bwlabeln: first input argument must be a 'logical' ND-array"); - return true; - } - - if (nargin == 2) - { - if (!args (1).is_real_scalar () && ! args(1).is_bool_type()) - { - error ("bwlabeln: second input argument must be a real scalar " - "or a 'logical' connectivity array"); - return true; - } - } - - return false; -} - -//debug -#include <iostream> -using namespace std; - -ostream& -operator<< (ostream& os, const coord& aidx) -{ - for (octave_idx_type i = 0; i < aidx.nelem (); i++) - os << aidx(i) + 1 << " "; - return os; -} - -set<coord> +std::set<coord> populate_neighbours(const boolNDArray& conn_mask) { - set<coord> neighbours; + std::set<coord> neighbours; dim_vector conn_size = conn_mask.dims (); coord centre(dim_vector(conn_size.length (), 1), 1); @@ -210,9 +163,114 @@ return neighbours; } +boolNDArray +get_mask(int N){ + bool* mask_ptr; + octave_idx_type n; + + static bool mask4[] = {0, 1, 0, + 1, 0, 1, + 0, 1, 0}; + + static bool mask8[] = {1, 1, 1, + 1, 0, 1, + 1, 0, 1}; + + static bool mask6[] = {0, 0, 0, + 0, 1, 0, + 0, 0, 0, + + 0, 1, 0, + 1, 0, 1, + 0, 1, 0, + + 0, 0, 0, + 0, 1, 0, + 0, 0, 0}; + + static bool mask18[] = {0, 1, 0, + 1, 1, 1, + 0, 1, 0, + + 1, 1, 1, + 1, 0, 1, + 1, 1, 1, + + 0, 1, 0, + 1, 1, 1, + 0, 1, 0}; + + static bool mask26[] = {1, 1, 1, + 1, 1, 1, + 1, 1, 1, + + 1, 1, 1, + 1, 0, 1, + 1, 1, 1, + + 1, 1, 1, + 1, 1, 1, + 1, 1, 1}; + + switch (N){ + case 4: + n = 2; + mask_ptr = mask4; + break; + case 8: + n = 2; + mask_ptr = mask8; + break; + case 6: + n = 3; + mask_ptr = mask6; + break; + case 18: + n = 3; + mask_ptr = mask18; + break; + case 26: + n = 3; + mask_ptr = mask26; + break; + default: + panic_impossible (); + } + + boolNDArray conn_mask; + if (n == 2) + { + conn_mask.resize (dim_vector (3, 3)); + for (octave_idx_type i = 0; i < 9; i++) + conn_mask(i) = mask_ptr[i]; + + } + else + { + conn_mask.resize (dim_vector (3, 3, 3)); + for (octave_idx_type i = 0; i < 27; i++) + conn_mask(i) = mask_ptr[i]; + } + + return conn_mask; +} + +boolNDArray +get_mask (const boolNDArray& BW) +{ + dim_vector mask_dims = BW.dims(); + for (auto i = 0; i < mask_dims.length (); i++) + mask_dims(i) = 3; + + return boolNDArray (mask_dims, 1); +} + +#include <iostream> + DEFUN_DLD(bwlabeln, args, , "\ -*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{l}, @var{num}] =} bwlabeln(@var{bw}, @var{n})\n\ +@deftypefn {Loadable Function} {[@var{l}, @var{num}] =} bwlabeln(@var{bw})\n\ +@deftypefnx {Loadable Function} {[@var{l}, @var{num}] =} bwlabeln(@var{bw}, @var{n})\n\ Label foreground objects in the n-dimensional binary image @var{bw}.\n\ \n\ The optional argument @var{n} sets the connectivity and defaults 26.\n\ @@ -230,27 +288,78 @@ union_find<coord, coord_hash> u_f; - if (any_bad_argument (args)) + octave_idx_type nargin = args.length (); + + if (nargin < 1 || nargin > 2) + { + print_usage (); return rval; + } - boolNDArray BW = args (0).bool_array_value (); + if (!args(0).is_bool_type ()) + { + error ("bwlabeln: first input argument must be a 'logical' ND-array"); + return rval; + } + boolNDArray BW = args(0).bool_array_value (); dim_vector size_vec = BW.dims (); - int nargin = args.length (); - //Connectivity mask boolNDArray conn_mask; - if( nargin == 1) - conn_mask = conn26; //Implement this properly later + + if (nargin == 2) + { + if (args(1).is_real_scalar ()) + { + double N = args(1).scalar_value (); + if (size_vec.length () == 2 && N != 4 && N != 8) + error ("bwlabeln: for 2d arrays, scalar N must be 4 or 8"); + else if (size_vec.length () == 3 && N != 6 && N != 18 && N != 26) + error ("bwlabeln: for 3d arrays, scalar N must be 4 or 8"); + else if (size_vec.length () > 3) + error ("bwlabeln: for higher-dimensional arrays, N must be a " + "connectivity mask"); + else + conn_mask = get_mask (N); + } + else if (args(2).is_bool_type() ) + { + conn_mask = args(2).bool_array_value (); + dim_vector conn_mask_dims = conn_mask.dims (); + if (conn_mask_dims.length () != size_vec.length ()) + error ("bwlabeln: connectivity mask N must have the same " + "dimensions as BW"); + for (octave_idx_type i = 0; i < conn_mask_dims.length (); i++) + { + if (conn_mask_dims(i) != 3) + { + error ("bwlabeln: connectivity mask N must have all " + "dimensions equal to 3"); + } + } + } + else + error ("bwlabeln: second input argument must be a real scalar " + "or a 'logical' connectivity array"); + } else - conn_mask = conn26; + // Get the maximal mask that has same number of dims as BW. + conn_mask = get_mask (BW); + if (error_state) + return rval; + + using std::set; + set<coord> neighbours = populate_neighbours(conn_mask); + std::cout << "Union-finding..." << std::endl;; + + bool* BW_vec = BW.fortran_vec (); for (octave_idx_type idx = 0; idx < BW.nelem (); idx++) { - if (BW(idx)) + if (BW_vec[idx]) { coord aidx = to_coord (size_vec, idx); @@ -259,7 +368,7 @@ //Replace this with C++0x range-based for loop later //(implemented in gcc 4.6) - for (auto nbr = neighbours.begin (); nbr!= neighbours.end (); nbr++) + for (auto nbr = neighbours.begin (); nbr != neighbours.end (); nbr++) { coord n = *nbr + aidx; if (in_range (n,size_vec) and BW(n) ) @@ -297,4 +406,3 @@ rval(1) = ids_to_label.size (); return rval; } -}//anonymous namespace This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jo...@us...> - 2012-09-04 21:29:33
|
Revision: 10962 http://octave.svn.sourceforge.net/octave/?rev=10962&view=rev Author: jordigh Date: 2012-09-04 21:29:27 +0000 (Tue, 04 Sep 2012) Log Message: ----------- Slight optimisations in bwlabeln.cc (use linear indices consistently) Modified Paths: -------------- trunk/octave-forge/main/image/src/bwlabeln.cc Modified: trunk/octave-forge/main/image/src/bwlabeln.cc =================================================================== --- trunk/octave-forge/main/image/src/bwlabeln.cc 2012-09-04 19:08:06 UTC (rev 10961) +++ trunk/octave-forge/main/image/src/bwlabeln.cc 2012-09-04 21:29:27 UTC (rev 10962) @@ -32,14 +32,6 @@ return true; } -bool in_range (const coord& a, const dim_vector& size_vec) -{ - for(octave_idx_type i = 0; i < a.nelem (); i++) - if (a(i) < 0 or a(i) >= size_vec(i)) - return false; - return true; -} - //Lexicographic order for coords bool operator< (const coord& a, const coord& b) { @@ -61,31 +53,12 @@ return true; } -struct coord_hash -{ - inline size_t operator() (const coord& c) const - { - size_t seed = 0; - for(octave_idx_type i = 0; i < c.nelem (); i++) - { - //Boost's hash - seed ^= c(i) + 0x9e3779b9 + (seed<<6) + (seed>>2); - } - return seed; - } - - inline size_t operator()(size_t s) const - { - return s; - } -}; - // A few basic utility functions //{ inline coord -to_coord(const dim_vector& dv, - octave_idx_type k) +to_coord (const dim_vector& dv, + octave_idx_type k) { octave_idx_type n = dv.length (); coord retval ( dim_vector (n, 1)); @@ -98,6 +71,21 @@ } inline +octave_idx_type +coord_to_pad_idx (const dim_vector& dv, + const coord& c) +{ + octave_idx_type idx = 0; + octave_idx_type mul = 1; + for (octave_idx_type j = 0; j < dv.length (); j++) + { + idx += mul*c(j); + mul *= dv(j) + 2; + } + return idx; +} + +inline coord operator+ (const coord& a, const coord& b) { @@ -139,28 +127,34 @@ } //} -std::set<coord> -populate_neighbours(const boolNDArray& conn_mask) +std::set<octave_idx_type> +populate_neighbours(const boolNDArray& conn_mask, + const dim_vector& size_vec) { + std::set<octave_idx_type> neighbours_idx; std::set<coord> neighbours; dim_vector conn_size = conn_mask.dims (); - coord centre(dim_vector(conn_size.length (), 1), 1); - coord zero(dim_vector(conn_size.length (), 1), 0); + coord centre (dim_vector(conn_size.length (), 1), 1); + coord zero (dim_vector(conn_size.length (), 1), 0); for (octave_idx_type idx = 0; idx < conn_mask.nelem (); idx++) { if (conn_mask(idx)) { - coord aidx = to_coord(conn_size, idx) - centre; + coord aidx = to_coord (conn_size, idx) - centre; + //The zero coordinates are the centre, and the negative ones //are the ones reflected about the centre, and we don't need //to consider those. if( aidx == zero or neighbours.find(-aidx) != neighbours.end() ) continue; + neighbours.insert (aidx); + + neighbours_idx.insert (coord_to_pad_idx(size_vec, aidx)); } } - return neighbours; + return neighbours_idx; } boolNDArray @@ -265,8 +259,23 @@ return boolNDArray (mask_dims, 1); } -#include <iostream> +octave_idx_type +get_padded_index (octave_idx_type r, + const dim_vector& dv) +{ + octave_idx_type mult = 1; + octave_idx_type padded = 0; + for (octave_idx_type j = 0; j < dv.length (); j++) + { + padded += mult*(r % dv(j) + 1); + mult *= dv(j) + 2; + r /= dv(j); + } + return padded; +} + + DEFUN_DLD(bwlabeln, args, , "\ -*- texinfo -*-\n\ @deftypefn {Loadable Function} {[@var{l}, @var{num}] =} bwlabeln(@var{bw})\n\ @@ -286,7 +295,7 @@ { octave_value_list rval; - union_find<coord, coord_hash> u_f; + union_find<octave_idx_type> u_f; octave_idx_type nargin = args.length (); @@ -350,40 +359,49 @@ if (error_state) return rval; - using std::set; + auto neighbours = populate_neighbours(conn_mask, size_vec); - set<coord> neighbours = populate_neighbours(conn_mask); + // Use temporary array with borders padded with zeros. Labels will + // also go in here eventually. + dim_vector padded_size = size_vec; + for (octave_idx_type j = 0; j < size_vec.length (); j++) + padded_size(j) += 2; - std::cout << "Union-finding..." << std::endl;; + NDArray L (padded_size, 0); - bool* BW_vec = BW.fortran_vec (); - for (octave_idx_type idx = 0; idx < BW.nelem (); idx++) + // L(2:end-1, 2:end, ..., 2:end-1) = BW + L.insert(BW, coord (dim_vector (size_vec.length (), 1), 1)); + + double* L_vec = L.fortran_vec (); + + for (octave_idx_type BWidx = 0; BWidx < BW.nelem (); BWidx++) { - if (BW_vec[idx]) + octave_idx_type Lidx = get_padded_index (BWidx, size_vec); + + if (L_vec[Lidx]) { - coord aidx = to_coord (size_vec, idx); - //Insert this one into its group - u_f.find_id(aidx); + u_f.find_id(Lidx); //Replace this with C++0x range-based for loop later //(implemented in gcc 4.6) for (auto nbr = neighbours.begin (); nbr != neighbours.end (); nbr++) { - coord n = *nbr + aidx; - if (in_range (n,size_vec) and BW(n) ) - u_f.unite (n,aidx); + octave_idx_type n = *nbr + Lidx; + if (L_vec[n] ) + u_f.unite (n, Lidx); } } } - NDArray L (size_vec, 0); + unordered_map<octave_idx_type, octave_idx_type> ids_to_label; octave_idx_type next_label = 1; auto idxs = u_f.get_objects (); //C++0x foreach later + for (auto idx = idxs.begin (); idx != idxs.end (); idx++) { octave_idx_type label; @@ -399,7 +417,7 @@ label = try_label -> second; } - L(idx->first) = label; + L_vec[idx->first] = label; } rval(0) = L; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jo...@us...> - 2012-09-07 15:13:42
|
Revision: 10978 http://octave.svn.sourceforge.net/octave/?rev=10978&view=rev Author: jordigh Date: 2012-09-07 15:13:33 +0000 (Fri, 07 Sep 2012) Log Message: ----------- bwlabeln: Fix type checking of inputs Modified Paths: -------------- trunk/octave-forge/main/image/src/bwlabeln.cc Modified: trunk/octave-forge/main/image/src/bwlabeln.cc =================================================================== --- trunk/octave-forge/main/image/src/bwlabeln.cc 2012-09-07 14:52:03 UTC (rev 10977) +++ trunk/octave-forge/main/image/src/bwlabeln.cc 2012-09-07 15:13:33 UTC (rev 10978) @@ -304,9 +304,9 @@ return rval; } - if (!args(0).is_bool_type ()) + if (!args(0).is_numeric_type () && !args(0).is_bool_type ()) { - error ("bwlabeln: first input argument must be a 'logical' ND-array"); + error ("bwlabeln: first input argument must be an ND array"); return rval; } @@ -331,7 +331,7 @@ else conn_mask = get_mask (N); } - else if (args(2).is_bool_type() ) + else if (args(2).is_numeric_type () || args(2).is_bool_type ()) { conn_mask = args(2).bool_array_value (); dim_vector conn_mask_dims = conn_mask.dims (); @@ -349,7 +349,7 @@ } else error ("bwlabeln: second input argument must be a real scalar " - "or a 'logical' connectivity array"); + "or a connectivity array"); } else // Get the maximal mask that has same number of dims as BW. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jo...@us...> - 2012-09-07 15:21:46
|
Revision: 10979 http://octave.svn.sourceforge.net/octave/?rev=10979&view=rev Author: jordigh Date: 2012-09-07 15:21:39 +0000 (Fri, 07 Sep 2012) Log Message: ----------- bwlabeln.cc: Remove dead code, reformat copyright, fix typo in mask8 Modified Paths: -------------- trunk/octave-forge/main/image/src/bwlabeln.cc Modified: trunk/octave-forge/main/image/src/bwlabeln.cc =================================================================== --- trunk/octave-forge/main/image/src/bwlabeln.cc 2012-09-07 15:13:33 UTC (rev 10978) +++ trunk/octave-forge/main/image/src/bwlabeln.cc 2012-09-07 15:21:39 UTC (rev 10979) @@ -1,17 +1,18 @@ -// Copyright (C) 2011 Jordi Gutiérrez Hermoso <jo...@oc...> +// Copyright (C) 2011-2012 Jordi Gutiérrez Hermoso <jo...@oc...> // -// 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 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. +// 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/>. +// You should have received a copy of the GNU General Public License +// along with this program; if not, see +// <http://www.gnu.org/licenses/>. // bwlabeln.cc --- @@ -88,20 +89,6 @@ inline coord -operator+ (const coord& a, const coord& b) -{ - octave_idx_type na = a.nelem (); - coord retval( dim_vector(na,1) ); - for (octave_idx_type i = 0; i < na; i++) - { - retval(i) = a(i) + b(i); - } - return retval; -} - - -inline -coord operator- (const coord& a, const coord& b) { octave_idx_type na = a.nelem (); @@ -169,7 +156,7 @@ static bool mask8[] = {1, 1, 1, 1, 0, 1, - 1, 0, 1}; + 1, 1, 1}; static bool mask6[] = {0, 0, 0, 0, 1, 0, @@ -264,6 +251,11 @@ get_padded_index (octave_idx_type r, const dim_vector& dv) { + // This function converts a linear index from the unpadded array + // into a linear index of the array with zero padding around it. I + // worked it out on paper, but if you want me to explain this, I'd + // have to work it out again. ;-) --jgh + octave_idx_type mult = 1; octave_idx_type padded = 0; for (octave_idx_type j = 0; j < dv.length (); j++) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |