Mercurial > hg > octave-image
view src/connectivity.cc @ 915:8c8ed7c4ab83 default tip
* bwlabeln.cc (bwlabel_nd): Fix small bug in comment
author | Jordi Gutiérrez Hermoso <jordigh@octave.org> |
---|---|
date | Tue, 18 Nov 2014 11:30:57 -0500 |
parents | f53cc3aaa88e |
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; connectivity::connectivity () { } connectivity::connectivity (const octave_value& val) { try {ctor (double_value (val));} catch (invalid_conversion& e) { try {ctor (bool_array_value (val));} catch (invalid_connectivity& e) {throw;} // so it does not get caught by the parent invalid_conversion catch (invalid_conversion& e) {throw invalid_connectivity ("must be logical or in [4 6 8 18 26]");} } return; } connectivity::connectivity (const boolNDArray& mask_arg) { ctor (mask_arg); return; } void connectivity::ctor (const boolNDArray& mask_arg) { mask = mask_arg; // Must be 1x1, 3x1, or 3x3x3x...x3 const octave_idx_type numel = mask.numel (); const octave_idx_type ndims = mask.ndims (); const dim_vector dims = mask.dims (); if (ndims == 2) { // Don't forget 1x1, and 3x1 which are valid but arrays always // have at least 2d if ( (dims(0) != 3 && dims(1) != 3) && (dims(0) != 3 && dims(1) != 1) && (dims(0) != 1 && dims(1) != 1)) throw invalid_connectivity ("is not 1x1, 3x1, 3x3, or 3x3x...x3"); } else { for (octave_idx_type i = 0; i < ndims; i++) if (dims(i) != 3) throw invalid_connectivity ("is not 3x3x...x3"); } // Center must be true const octave_idx_type center = floor (numel /2); if (! mask(center)) throw invalid_connectivity ("center is not true"); // 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]) throw invalid_connectivity ("is not symmetric relative to its center"); return; } connectivity::connectivity (const octave_idx_type& conn) { ctor (conn); return; } void connectivity::ctor (const octave_idx_type& conn) { if (conn == 4) { mask = boolNDArray (dim_vector (3, 3), true); bool* md = mask.fortran_vec (); md[ 0] = false; md[ 2] = false; md[ 6] = false; md[ 8] = false; } else if (conn == 6) { mask = boolNDArray (dim_vector (3, 3, 3), false); bool* md = mask.fortran_vec (); md[ 4] = true; md[10] = true; md[12] = true; md[13] = true; md[14] = true; md[16] = true; md[22] = true; } else if (conn == 8) mask = boolNDArray (dim_vector (3, 3), true); else if (conn == 18) { mask = boolNDArray (dim_vector (3, 3, 3), true); bool* md = mask.fortran_vec (); md[ 0] = false; md[ 2] = false; md[ 6] = false; md[ 8] = false; md[18] = false; md[20] = false; md[24] = false; md[26] = false; } else if (conn == 26) mask = boolNDArray (dim_vector (3, 3, 3), true); else throw invalid_connectivity ("must be in the set [4 6 8 18 26]"); return; } connectivity::connectivity (const octave_idx_type& ndims, const std::string& type) { dim_vector size; if (ndims == 1) size = dim_vector (3, 1); else { size = dim_vector (3, 3); size.resize (ndims, 3); } if (type == "maximal") { mask = boolNDArray (size, true); } else if (type == "minimal") { mask = boolNDArray (size, false); bool* md = mask.fortran_vec (); md += int (floor (pow (3, ndims) /2)); // move to center md[0] = true; for (octave_idx_type dim = 0; dim < ndims; dim++) { const octave_idx_type stride = pow (3, dim); md[ stride] = true; md[-stride] = true; } } else throw invalid_connectivity ("must be \"maximal\" or \"minimal\""); return; } Array<octave_idx_type> connectivity::offsets (const dim_vector& size) const { const octave_idx_type nnz = mask.nnz (); const octave_idx_type ndims = mask.ndims (); const dim_vector dims = mask.dims (); Array<octave_idx_type> offsets (dim_vector (nnz, 1)); // retval const dim_vector cum_size = size.cumulative (); Array<octave_idx_type> diff (dim_vector (ndims, 1)); Array<octave_idx_type> sub (dim_vector (ndims, 1), 0); for (octave_idx_type ind = 0, found = 0; found < nnz; ind++, boolNDArray::increment_index (sub, dims)) { if (mask(ind)) { for (octave_idx_type i = 0; i < ndims; 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++) off += (diff(dim) * cum_size(dim-1)); offsets(found) = off; found++; } } return offsets; } double connectivity::double_value (const octave_value& val) { const double conn = val.double_value (); // Check is_scalar_type because the warning Octave:array-to-scalar // is off by default and we will get the first element only. if (error_state || ! val.is_scalar_type ()) throw invalid_conversion ("no conversion to double value"); return conn; } boolNDArray connectivity::bool_array_value (const octave_value& val) { const boolNDArray mask = val.bool_array_value (); // bool_array_value converts anything other than 0 to true, which will // then validate as conn array, hence any_element_not_one_or_zero() if (val.array_value ().any_element_not_one_or_zero ()) throw invalid_conversion ("no conversion to bool array value"); return mask; }