implemented isolation/triangulation. needs to be tested
This commit is contained in:
parent
2d5ff2fbe1
commit
c71f86a33b
72
field.py
72
field.py
|
|
@ -615,6 +615,7 @@ class BinaryFieldNd:
|
||||||
self.labels = None
|
self.labels = None
|
||||||
self.nlabels = 0
|
self.nlabels = 0
|
||||||
self.wrap = tuple(self._ndim*[None])
|
self.wrap = tuple(self._ndim*[None])
|
||||||
|
self._feat_slice = None
|
||||||
self.set_structure(False)
|
self.set_structure(False)
|
||||||
self.set_periodicity(self._ndim*[False])
|
self.set_periodicity(self._ndim*[False])
|
||||||
|
|
||||||
|
|
@ -653,6 +654,7 @@ class BinaryFieldNd:
|
||||||
self.labels,self.nlabels,self.wrap = self._labels_periodic()
|
self.labels,self.nlabels,self.wrap = self._labels_periodic()
|
||||||
else:
|
else:
|
||||||
self.labels,self.nlabels = ndimage.label(self.data,structure=self.structure)
|
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):
|
def _labels_periodic(self,map_to_zero=False):
|
||||||
'''Label features in an array while taking into account periodic wrapping.
|
'''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
|
self.data = self._labels_periodic(map_to_zero=True)[0]>0
|
||||||
# Invert to get the final result
|
# Invert to get the final result
|
||||||
np.logical_not(self.data,self.data)
|
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):
|
def probe(self,idx):
|
||||||
'''Returns whether or not a point at idx is True or False.'''
|
'''Returns whether or not a point at idx is True or False.'''
|
||||||
|
|
@ -757,6 +762,9 @@ class BinaryFieldNd:
|
||||||
self.label()
|
self.label()
|
||||||
if label is None:
|
if label is None:
|
||||||
return np.bincount(self.labels.ravel())
|
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:
|
else:
|
||||||
return np.sum(self.labels==label)
|
return np.sum(self.labels==label)
|
||||||
|
|
||||||
|
|
@ -775,27 +783,75 @@ class BinaryFieldNd:
|
||||||
self.label()
|
self.label()
|
||||||
selection = self._select_feature(selection)
|
selection = self._select_feature(selection)
|
||||||
# Map tagged regions to zero in order to discard them
|
# 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
|
map_[selection] = 0
|
||||||
# Remove gaps from target mapping
|
# 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
|
# Discard regions
|
||||||
self.labels = map_[self.labels]
|
self.labels = map_[self.labels]
|
||||||
self.nlabels = np.max(map_)
|
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):
|
def _select_feature(self,selection):
|
||||||
dtype = self.label.dtype
|
dtype = self.labels.dtype
|
||||||
if np.issubdtype(type(selection),np.integer):
|
if selection is None:
|
||||||
return np.array(selection,dtype=dtype)
|
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)):
|
elif isinstance(selection,(list,tuple,np.ndarray)):
|
||||||
selection = np.array(selection)
|
selection = np.array(selection)
|
||||||
if selection.dtype==np.dtype('bool'):
|
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."
|
"Boolean indexing must provide count+1 values."
|
||||||
else:
|
else:
|
||||||
selection = selection.astype(dtype)
|
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."
|
"Entry in selection is out-of-bounds."
|
||||||
return selection
|
return selection
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue