# Copyright (C) 2003-2005 Peter J. Verveer # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # 3. The name of the author may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import types import math import numarray import _ni_support import _nd_image import morphology from numarray.generic import _broadcast def label(input, structure = None, output = None): """Label an array of objects. The structure that defines the object connections must be symmetric. If no structuring element is provided an element is generated with a squared connectivity equal to one. This function returns a tuple consisting of the array of labels and the number of objects found. If an output array is provided only the number of objects found is returned. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if structure == None: structure = morphology.generate_binary_structure(input.rank, 1) structure = numarray.asarray(structure, type = numarray.Bool) if structure.rank != input.rank: raise RuntimeError, 'structure and input must have equal rank' for ii in structure.shape: if ii != 3: raise RuntimeError, 'structure dimensions must be equal to 3' if not structure.iscontiguous(): structure = structure.copy() if isinstance(output, numarray.NumArray): if output.type() != numarray.Int32: raise RuntimeError, 'output type must be Int32' else: output = numarray.Int32 output, return_value = _ni_support._get_output(output, input) max_label = _nd_image.label(input, structure, output) if return_value == None: return max_label else: return return_value, max_label def find_objects(input, max_label = 0): """Find objects in a labeled array. The input must be an array with labeled objects. A list of slices into the array is returned that contain the objects. The list represents a sequence of the numbered objects. If a number is missing, None is returned instead of a slice. If max_label > 0, it gives the largest object number that is searched for, otherwise all are returned. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if max_label < 1: max_label = input.max() return _nd_image.find_objects(input, max_label) def sum(input, labels = None, index = None): """Calculate the sum of the values of the array. The index parameter is a single label number or a sequence of label numbers of the objects to be measured. If index is None, all values are used where labels is larger than zero. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if labels != None: labels = numarray.asarray(labels) labels = _broadcast(labels, input.shape) if labels.shape != input.shape: raise RuntimeError, 'input and labels shape are not equal' return _nd_image.statistics(input, labels, index, 0) def mean(input, labels = None, index = None): """Calculate the mean of the values of the array. The index parameter is a single label number or a sequence of label numbers of the objects to be measured. If index is None, all values are used where labels is larger than zero. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if labels != None: labels = numarray.asarray(labels) labels = _broadcast(labels, input.shape) if labels.shape != input.shape: raise RuntimeError, 'input and labels shape are not equal' return _nd_image.statistics(input, labels, index, 1) def variance(input, labels = None, index = None): """Calculate the variance of the values of the array. The index parameter is a single label number or a sequence of label numbers of the objects to be measured. If index is None, all values are used where labels is larger than zero. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if labels != None: labels = numarray.asarray(labels) labels = _broadcast(labels, input.shape) if labels.shape != input.shape: raise RuntimeError, 'input and labels shape are not equal' return _nd_image.statistics(input, labels, index, 2) def standard_deviation(input, labels = None, index = None): """Calculate the standard deviation of the values of the array. The index parameter is a single label number or a sequence of label numbers of the objects to be measured. If index is None, all values are used where labels is larger than zero. """ var = variance(input, labels, index) if (isinstance(var, types.ListType)): return [math.sqrt(x) for x in var] else: return math.sqrt(var) def minimum(input, labels = None, index = None): """Calculate the minimum of the values of the array. The index parameter is a single label number or a sequence of label numbers of the objects to be measured. If index is None, all values are used where labels is larger than zero. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if labels != None: labels = numarray.asarray(labels) labels = _broadcast(labels, input.shape) if labels.shape != input.shape: raise RuntimeError, 'input and labels shape are not equal' return _nd_image.statistics(input, labels, index, 3) def maximum(input, labels = None, index = None): """Calculate the maximum of the values of the array. The index parameter is a single label number or a sequence of label numbers of the objects to be measured. If index is None, all values are used where labels is larger than zero. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if labels != None: labels = numarray.asarray(labels) labels = _broadcast(labels, input.shape) if labels.shape != input.shape: raise RuntimeError, 'input and labels shape are not equal' return _nd_image.statistics(input, labels, index, 4) def _index_to_position(index, shape): """Convert a linear index to a position""" if len(shape) > 0: pos = [] stride = numarray.multiply.reduce(shape) for size in shape: stride = stride // size pos.append(index // stride) index -= pos[-1] * stride return tuple(pos) else: return 0 def minimum_position(input, labels = None, index = None): """Find the position of the minimum of the values of the array. The index parameter is a single label number or a sequence of label numbers of the objects to be measured. If index is None, all values are used where labels is larger than zero. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if labels != None: labels = numarray.asarray(labels) labels = _broadcast(labels, input.shape) if labels.shape != input.shape: raise RuntimeError, 'input and labels shape are not equal' pos = _nd_image.statistics(input, labels, index, 5) if (isinstance(pos, types.ListType)): return [_index_to_position(x, input.shape) for x in pos] else: return _index_to_position(pos, input.shape) def maximum_position(input, labels = None, index = None): """Find the position of the maximum of the values of the array. The index parameter is a single label number or a sequence of label numbers of the objects to be measured. If index is None, all values are used where labels is larger than zero. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if labels != None: labels = numarray.asarray(labels) labels = _broadcast(labels, input.shape) if labels.shape != input.shape: raise RuntimeError, 'input and labels shape are not equal' pos = _nd_image.statistics(input, labels, index, 6) if (isinstance(pos, types.ListType)): return [_index_to_position(x, input.shape) for x in pos] else: return _index_to_position(pos, input.shape) def extrema(input, labels = None, index = None): """Calculate the minimum, the maximum and their positions of the values of the array. The index parameter is a single label number or a sequence of label numbers of the objects to be measured. If index is None, all values are used where labels is larger than zero. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if labels != None: labels = numarray.asarray(labels) labels = _broadcast(labels, input.shape) if labels.shape != input.shape: raise RuntimeError, 'input and labels shape are not equal' min, max, minp, maxp = _nd_image.statistics(input, labels, index, 7) if (isinstance(minp, types.ListType)): minp = [_index_to_position(x, input.shape) for x in minp] maxp = [_index_to_position(x, input.shape) for x in maxp] else: minp = _index_to_position(minp, input.shape) maxp = _index_to_position(maxp, input.shape) return min, max, minp, maxp def center_of_mass(input, labels = None, index = None): """Calculate the center of mass of of the array. The index parameter is a single label number or a sequence of label numbers of the objects to be measured. If index is None, all values are used where labels is larger than zero. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if labels != None: labels = numarray.asarray(labels) labels = _broadcast(labels, input.shape) if labels.shape != input.shape: raise RuntimeError, 'input and labels shape are not equal' return _nd_image.center_of_mass(input, labels, index) def histogram(input, min, max, bins, labels = None, index = None): """Calculate a histogram of of the array. The histogram is defined by its minimum and maximum value and the number of bins. The index parameter is a single label number or a sequence of label numbers of the objects to be measured. If index is None, all values are used where labels is larger than zero. """ input = numarray.asarray(input) if isinstance(input.type(), numarray.ComplexType): raise TypeError, 'Complex type not supported' if labels != None: labels = numarray.asarray(labels) labels = _broadcast(labels, input.shape) if labels.shape != input.shape: raise RuntimeError, 'input and labels shape are not equal' if bins < 1: raise RuntimeError, 'number of bins must be >= 1' if min >= max: raise RuntimeError, 'min must be < max' return _nd_image.histogram(input, min, max, bins, labels, index) def watershed_ift(input, markers, structure = None, output = None): """Apply watershed from markers using a iterative forest transform algorithm. Negative markers are considered background markers which are processed after the other markers. A structuring element defining the connectivity of the object can be provided. If none is provided an element is generated iwth a squared connecitiviy equal to one. An output array can optionally be provided. """ input = numarray.asarray(input) if input.type() not in [numarray.UInt8, numarray.UInt16]: raise TypeError, 'only 8 and 16 unsigned inputs are supported' if structure == None: structure = morphology.generate_binary_structure(input.rank, 1) structure = numarray.asarray(structure, type = numarray.Bool) if structure.rank != input.rank: raise RuntimeError, 'structure and input must have equal rank' for ii in structure.shape: if ii != 3: raise RuntimeError, 'structure dimensions must be equal to 3' if not structure.iscontiguous(): structure = structure.copy() markers = numarray.asarray(markers) if input.shape != markers.shape: raise RuntimeError, 'input and markers must have equal shape' if not isinstance(markers.type(), numarray.IntegralType): raise RuntimeError, 'marker should be of integer type' if isinstance(output, numarray.NumArray): if not isinstance(output.type(), numarray.IntegralType): raise RuntimeError, 'output should be of integer type' else: output = markers.type() output, return_value = _ni_support._get_output(output, input) _nd_image.watershed_ift(input, markers, structure, output) return return_value