find_small_clusters#
Identifies clusters of trapped voxels smaller than a given size and rolls them back to invaded. This is typically used to clean up pixel-scale noise after trapping analysis.
import matplotlib.pyplot as plt
import numpy as np
import porespy as ps
ps.visualization.set_mpl_style()
The arguments and their defaults are. Note that the function takes the original image and a separate boolean mask of the trapped voxels.
import inspect
inspect.signature(ps.filters.find_small_clusters)
<Signature (im: numpy.ndarray[tuple[typing.Any, ...], numpy.dtype[~_ScalarT]], trapped: numpy.ndarray[tuple[typing.Any, ...], numpy.dtype[~_ScalarT]] = None, min_size: int = 1, conn: str = 'min')>
Set up a drainage simulation with trapping so we have a realistic trapped mask to feed in. Trapping at the pixel scale typically produces some single- and few-voxel artefacts along solid walls.
np.random.seed(0)
im = ps.generators.blobs(shape=[300, 300], porosity=0.65, seed=2)
im = ps.filters.fill_closed_pores(im)
inlets = ps.generators.faces(im.shape, inlet=0)
outlets = ps.generators.faces(im.shape, outlet=0)
pc = ps.filters.capillary_transform(
im=im, sigma=0.072, theta=180, voxel_size=1e-5)
drn = ps.simulations.drainage(im=im, pc=pc, inlets=inlets, outlets=outlets)
trapped = drn.im_seq == -1
fig, ax = plt.subplots(figsize=[5, 5])
ax.imshow(trapped, origin='lower', interpolation='none')
ax.set_title('trapped voxels')
ax.axis(False);
min_size#
Trapped clusters with this many voxels or fewer are released. Larger values release more, until at some point only the largest trapped regions remain.
fig, ax = plt.subplots(1, 3, figsize=[15, 5])
for axis, min_size in zip(ax, [1, 5, 25]):
res = ps.filters.find_small_clusters(
im=im, trapped=trapped.copy(), min_size=min_size)
axis.imshow(res.im_trapped, origin='lower', interpolation='none')
axis.set_title(f'min_size = {min_size}')
axis.axis(False)
conn#
Controls voxel connectivity used to define a cluster. 'min' (default) requires shared faces; 'max' accepts edges and corners. Looser connectivity merges neighbouring clusters and so reduces the number of voxels released for a given min_size.
res_min = ps.filters.find_small_clusters(
im=im, trapped=trapped.copy(), min_size=5, conn='min')
res_max = ps.filters.find_small_clusters(
im=im, trapped=trapped.copy(), min_size=5, conn='max')
fig, ax = plt.subplots(1, 2, figsize=[10, 5])
ax[0].imshow(res_min.im_small, origin='lower', interpolation='none')
ax[0].set_title("conn = 'min'")
ax[0].axis(False)
ax[1].imshow(res_max.im_small, origin='lower', interpolation='none')
ax[1].set_title("conn = 'max'")
ax[1].axis(False);
Returned attributes#
find_small_clusters returns a Results object with two boolean images: im_small flags the released voxels, and im_trapped is the input mask with those voxels switched off.
res = ps.filters.find_small_clusters(
im=im, trapped=trapped.copy(), min_size=5)
print('voxels released:', int(res.im_small.sum()))
print('voxels still trapped:', int(res.im_trapped.sum()))
voxels released: 124
voxels still trapped: 12155