implemented isolation/triangulation. needs to be tested

This commit is contained in:
Michael Krayer 2021-08-06 00:34:32 +02:00
parent 2d5ff2fbe1
commit c71f86a33b
1 changed files with 64 additions and 8 deletions

View File

@ -615,6 +615,7 @@ class BinaryFieldNd:
self.labels = None
self.nlabels = 0
self.wrap = tuple(self._ndim*[None])
self._feat_slice = None
self.set_structure(False)
self.set_periodicity(self._ndim*[False])
@ -653,6 +654,7 @@ class BinaryFieldNd:
self.labels,self.nlabels,self.wrap = self._labels_periodic()
else:
self.labels,self.nlabels = ndimage.label(self.data,structure=self.structure)
self._feat_slice = ndimage.find_objects(self.labels)
def _labels_periodic(self,map_to_zero=False):
'''Label features in an array while taking into account periodic wrapping.
@ -735,6 +737,9 @@ class BinaryFieldNd:
self.data = self._labels_periodic(map_to_zero=True)[0]>0
# Invert to get the final result
np.logical_not(self.data,self.data)
# If labels have been computed already, recompute them to stay consistent
if self.labels is not None:
self.label()
def probe(self,idx):
'''Returns whether or not a point at idx is True or False.'''
@ -757,6 +762,9 @@ class BinaryFieldNd:
self.label()
if label is None:
return np.bincount(self.labels.ravel())
# TBD: compare performance with
# sizes = ndimage.sum(mask, label_im, range(nb_labels + 1))
# http://scipy-lectures.org/advanced/image_processing/auto_examples/plot_find_object.html
else:
return np.sum(self.labels==label)
@ -775,27 +783,75 @@ class BinaryFieldNd:
self.label()
selection = self._select_feature(selection)
# Map tagged regions to zero in order to discard them
map_ = np.array(range(0,self.count+1),dtype=self.label.dtype)
map_ = np.array(range(self.nlabels+1),dtype=self.labels.dtype)
map_[selection] = 0
# Remove gaps from target mapping
map_ = np.unique(map_,return_inverse=True)[1]
idx_,map_ = np.unique(map_,return_index=True,return_inverse=True)[1:3]
# Discard regions
self.labels = map_[self.labels]
self.nlabels = np.max(map_)
self.data = self.labels>0
for axis in range(self._ndim):
if self.wrap[axis] is not None:
self.wrap[axis] = self.wrap[axis][idx_]
self.data = self.labels>0
def isolate_feature(self,selection):
from scipy import ndimage
if self.labels is None:
self.label()
selection = self._select_feature(selection)
output = []
for lab_ in selection:
# Extract feature of interest
if lab_==0:
data_ = np.logical_not(self.data)
else:
data_ = (self.labels[self._feat_slice[lab_-1]]==lab_)
# If feature is wrapped periodically, duplicate it and extract
# largest one
iswrapped = False
rep_ = self._ndim*[1]
for axis in range(self._ndim):
if self.wrap[axis] is not None and self.wrap[axis][lab_]:
rep_[axis] = 2
iswrapped = True
if iswrapped:
data_ = np.tile(data_,rep_)
l_,nl_ = ndimage.label(data_,structure=self.structure)
vol_ = np.bincount(l_.ravel())
il_ = np.argmax(vol_[1:])+1
sl_ = ndimage.find_objects(l_==il_)[0]
data_ = data_[sl_]
# Add to output
output.append(data_)
return output
def triangulate_feature(self,selection,origin=(0,0,0),spacing=(1,1,1)):
assert self._ndim==3, "Triangulation requires 3D data."
if self.labels is None:
self.label()
selection = self._select_feature(selection)
output = []
pw = tuple((1,1) for ii in range(self._ndim))
for lab_ in selection:
data_ = np.pad(self.isolate_feature(lab_)[0],pw,mode='constant')
output.append(Field3d(data_,origin,spacing).vtk_contour(0.5))
return output
def _select_feature(self,selection):
dtype = self.label.dtype
if np.issubdtype(type(selection),np.integer):
return np.array(selection,dtype=dtype)
dtype = self.labels.dtype
if selection is None:
return np.array(range(1,self.nlabels+1))
elif np.issubdtype(type(selection),np.integer):
return np.array(selection,dtype=dtype,ndmin=1)
elif isinstance(selection,(list,tuple,np.ndarray)):
selection = np.array(selection)
if selection.dtype==np.dtype('bool'):
assert selection.ndim==1 and selection.shape[0]==self.count+1,\
assert selection.ndim==1 and selection.shape[0]==self.nlabels+1,\
"Boolean indexing must provide count+1 values."
else:
selection = selection.astype(dtype)
assert np.max(selection)<=self.count and np.min(selection)>=0,\
assert np.max(selection)<=self.nlabels and np.min(selection)>=0,\
"Entry in selection is out-of-bounds."
return selection
else: