diff --git a/field.py b/field.py index 7de8769..6decfe7 100644 --- a/field.py +++ b/field.py @@ -648,109 +648,82 @@ def gaussian_filter_umean_channel(array,spacing,sigma,truncate=4.0): class Features3d: - def __init__(self,input,threshold,origin,spacing,periodicity,invert=False,has_ghost=False): + def __init__(self,input,threshold,origin,spacing,periodicity, + invert=False,has_ghost=False,keep_input=False, + contour_method='flying_edges',cellvol_normal_component=2, + report=False): assert len(origin)==3, "'origin' must be of length 3" assert len(spacing)==3, "'spacing' must be of length 3" assert len(periodicity)==3, "'periodicity' must be of length 3" assert isinstance(input,np.ndarray), "'input' must be numpy.ndarray." # Assign basic properties to class variables - self.origin = tuple(float(x) for x in origin) - self.spacing = tuple(float(x) for x in spacing) + self.origin = np.array(origin,dtype=np.float) + self.spacing = np.array(spacing,dtype=np.float) + self.dimensions = input.shape self.periodicity = tuple(bool(x) for x in periodicity) - self._invert = invert - self._sldata = tuple(slice(0,-1) if x else None for x in periodicity) # If regions are supposed to be inverted, i.e. the interior consists of values # smaller than the threshold instead of larger, change the sign of the array. sign_invert = -1 if invert else +1 self._threshold = sign_invert*threshold - # '_data' is the array which is to be triangulated. Here one trailing ghost cell is + # '_input' is the array which is to be triangulated. Here one trailing ghost cell is # required to get closed surfaces. The data will always be copied since it probably # needs to be copied for vtk anyway (needs FORTRAN contiguous array) and this way # there will never be side effects on the input data. if has_ghost: - self._data = sign_invert*input + self._input = sign_invert*input else: pw = tuple((0,1) if x else (0,0) for x in periodicity) - self._data = np.pad(sign_invert*input,pw,mode='wrap') - - + self._input = np.pad(sign_invert*input,pw,mode='wrap') + # Triangulate + self.triangulate(contour_method=contour_method, + cellvol_normal_component=cellvol_normal_component, + report=report) + # Drop input if requested: this may free memory in case it was copied/temporary. + if not keep_input: self._input = None + return @classmethod - def from_field(cls,fld,threshold,periodicity,invert=False,has_ghost=False): - return cls(fld.data,threshold,fld.origin,fld.spacing,periodicity,invert=invert,has_ghost=has_ghost) + def from_field(cls,fld,threshold,periodicity,invert=False,has_ghost=False, + keep_input=False,contour_method='flying_edges', + cellvol_normal_component=2,report=False): + return cls(fld.data,threshold,fld.origin,fld.spacing,periodicity, + invert=invert,has_ghost=has_ghost,keep_input=keep_input, + contour_method=contour_method, + cellvol_normal_component=cellvol_normal_component, + report=report) - @property - def threshold(self): return self._threshold - - @property - def points(self): return self._points - - @property - def faces(self): return self._faces - - @property - def nfeatures(self): return self._nfeatures - - def fill_holes(self): - # Check if volume negative -> cell normal direction - - # self.binary.fill_holes() - # li = ndimage.binary_erosion(self.binary._data) - # self._data[li] = 2*self._threshold # arbitrary, only needs to be above threshold - # if self._faces is not None: - # self.triangulate(contour_method=self.__TRI_CONTMETH, - # cellvol_normal_component=self.__TRI_NORMCOMP) - return - - def reduce_noise(self,threshold=1e-5,is_relative=True): - '''Removes all objects with smaller (binary-based) volume than a threshold.''' - # if is_relative: - # threshold = threshold*self.binary.volume_domain() - # vol = self.binary.volumes() - # li = vol