From fd2312247016b25ae69de738e197ae60c88493e5 Mon Sep 17 00:00:00 2001 From: Michael Krayer Date: Tue, 10 Aug 2021 02:17:58 +0200 Subject: [PATCH] Features3d now fully based on triangulation: needs to be tested and some routines implemented --- field.py | 159 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 105 insertions(+), 54 deletions(-) diff --git a/field.py b/field.py index 7ad0200..7de8769 100644 --- a/field.py +++ b/field.py @@ -648,13 +648,11 @@ def gaussian_filter_umean_channel(array,spacing,sigma,truncate=4.0): class Features3d: - def __init__(self,input,threshold,origin,spacing,periodicity,connect_diagonals=True,invert=False,has_ghost=False): + def __init__(self,input,threshold,origin,spacing,periodicity,invert=False,has_ghost=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." - # Import libraries - import pyvista as pv # Assign basic properties to class variables self.origin = tuple(float(x) for x in origin) self.spacing = tuple(float(x) for x in spacing) @@ -664,26 +662,17 @@ class Features3d: # 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 = threshold + self._threshold = sign_invert*threshold # '_data' 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 = np.asfortranarray(sign_invert*input) + self._data = sign_invert*input else: pw = tuple((0,1) if x else (0,0) for x in periodicity) - self._data = np.asfortranarray(np.pad(sign_invert*input,pw,mode='wrap')) - # 'binary' is a BinaryField which determines the connectivity of regions - # and provides morphological manipulations. - self.binary = BinaryFieldNd(self._data>=self._threshold,periodicity, - connect_diagonals=connect_diagonals, - deep=False,has_ghost=has_ghost) - # Compute features in 'binary' by labeling. - self.binary.label() - # Set arrays produced by triangulation to None - self._points = None - self._faces = None + self._data = np.pad(sign_invert*input,pw,mode='wrap') + @classmethod @@ -700,32 +689,36 @@ class Features3d: def faces(self): return self._faces @property - def nfeatures(self): return self.binary.nlabels + def nfeatures(self): return self._nfeatures def fill_holes(self): - 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) + # 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