Skip to content

Network Extraction

A pore network reduces the pore space to a graph: pores are nodes, wide regions with a size, volume and position, and throats are edges, the constrictions that connect pairs of pores. Networks are compact (a 1000³ image becomes a few hundred thousand pores) and fast to simulate, and their pore and throat statistics are a common language for describing microstructure.

  • Solves segmentation of the pore space into pores and throats
  • Backends PoreSpy on CPU, with SNOW2 (watershed, default) or MAGNET (medial axis)
  • Reports a network with pore and throat properties, and its pore and throat counts
  • How to run it Network Extraction in the User guide

PoreStore runs PoreSpy's extraction algorithms.3 The papers below describe them in full. This page covers what PoreStore passes them and what comes back.

The problem being solved

The result is a graph whose nodes are pores and whose edges are throats, each with geometric properties measured on the image. SNOW2 makes each region of a watershed of the distance transform a pore, and each pair of touching regions a throat; MAGNET puts pores at the junctions and ends of the pore space's medial axis, and throats along the branches between them.

A 260 × 260 synthetic sample, porosity 0.62, run through PoreStore's own extraction code with the suggested settings, and extracted and drawn in two dimensions so the pores are easy to see. Left: SNOW2 splits the pore space into regions, one per pore, and each region becomes a node; regions that share a boundary are joined by a throat. Middle: the SNOW2 network, with a boundary width of 3, so the image is padded by 3 voxels on every face and the pores in that frame are the boundary pores. Right: MAGNET on the same image, from the skeleton of the pore space, with no boundary pores. Node size shows each pore's inscribed diameter.

The backends

The default. SNOW (Sub-Network of an Over-segmented Watershed)1 splits the pore space into regions with a marker-based watershed of the distance transform:

  1. Compute the distance transform \(d(\mathbf{x})\) of the pore space.
  2. Smooth it with a Gaussian of width \(\sigma\) (Gaussian sigma) to suppress spurious peaks on rough walls.
  3. Find peaks with a maximum filter of radius \(r_\text{max}\) (Peak filter radius). These are candidate pore centres.
  4. Remove peaks on saddles and plateaus, and merge peaks that are too close together. This step corrects the watershed's tendency to over-segment.
  5. Flood \(-d\) from the remaining peaks. Each basin is one pore region.

Each region becomes a pore, and each pair of touching regions becomes a throat whose size comes from their shared boundary. Layers of boundary pores, \(w_b\) voxels thick (Boundary width), are added on all six faces, labelled xmin, xmax and so on, which simulations can use as inlets and outlets. PoreStore's Network Validation doesn't read these labels: it picks its own inlet and outlet pores.

Setting Symbol Suggested
Boundary width (voxels) \(w_b\) 3
Accuracy Standard
Gaussian sigma \(\sigma\) 0.4
Peak filter radius (r_max) \(r_\text{max}\) 4

With Accuracy set to Standard, volumes and areas are voxel counts. High measures them on marching-cubes surfaces, which is slower but less biased (see Interfacial Surface Area).

Pore property Meaning
pore.coords Centre of mass
pore.volume, pore.region_volume Volume (voxel count)
pore.equivalent_diameter Diameter of a sphere of the same volume, \(2(3V/4\pi)^{1/3}\)
pore.inscribed_diameter Twice the largest distance to solid inside the region
pore.extended_diameter Twice the largest global distance-transform value in the region's bounding box
pore.surface_area Pore–solid surface area
Throat property Meaning
throat.conns The two pores it joins
throat.inscribed_diameter Twice the largest distance to solid on the shared boundary
throat.cross_sectional_area Area of the shared boundary
throat.equivalent_diameter Diameter of a circle of that area, \(\sqrt{4A/\pi}\)
throat.total_length, throat.direct_length Pore-to-throat-to-pore and straight-line lengths
throat.perimeter Perimeter of the shared boundary

The network file also holds pore.geometric_centroid (the centre of mass again), pore.local_peak and pore.global_peak (where the region's own distance transform, and the global one in its bounding box, are largest), pore.region_label (the watershed region number), pore.phase and throat.phases (the phase of each pore, and of the two pores a throat joins), throat.global_peak (where the distance transform is largest on the shared boundary), and pore.all, throat.all, param.voxel_size and param.ndim. With boundary pores, pore.boundary marks all of them and pore.xmin to pore.zmax each face. A multi-phase image adds a label for each phase, such as pore.void, pore.solid and throat.solid_void.

MAGNET (Medial Axis Guided Network Extraction Tool)2 starts from the skeleton of the pore space instead of from a watershed:

  1. Skeletonise the pore space to its medial axis, optionally after trimming solid pieces that float free of the rest (Trim floating surface solids).
  2. Junctions and end points of the skeleton become pores. Junctions closer together than the local pore size, or than \(s\) (Junction merge threshold) if it's given, are merged.
  3. Long skeleton branches between junctions are split with extra pores, by a maximum filter of length \(\ell_\text{max}\) (Throat max-filter length) or by fast marching (Throat junction mode).
  4. Optionally (Compute throat area), random walkers measure the cross-sectional area of each irregular throat, which gives a better hydraulic diameter. Throat area walkers, Throat area step size and Throat area max steps set how many walkers run, how far each step goes and how many steps each takes.
Setting Symbol Suggested
Junction merge threshold (s) \(s\) chosen from the local pore size
Throat max-filter length (l_max) \(\ell_\text{max}\) 7
Throat area walkers 10
Throat area step size 0.5

MAGNET preserves the topology of the pore space by construction, and is faster than SNOW on large images. Pores get pore.coords, pore.inscribed_diameter, pore.equivalent_diameter and pore.index. Throats get throat.conns, throat.actual_length, throat.area, the diameters throat.max_diameter, throat.min_diameter, throat.avg_diameter, throat.inscribed_diameter and throat.integrated_diameter, and throat.equivalent_diameter only when Compute throat area is on. A MAGNET network has no boundary-pore labels.

Units

Extraction runs on the voxel grid. The network file states its unit: sizes are in micrometres when the image had a voxel size at extraction, and in voxels otherwise, in which case lengths scale with the voxel size, areas with its square and volumes with its cube. The job page says which applies. See Units and voxel size.

Reproducibility

Extraction is deterministic: the same image and settings give the same network every time. Networks extracted before 22 October 2026 can differ slightly from a new extraction of the same image: a few pores of a SNOW2 network are split differently, and MAGNET pore centres can sit on a different voxel of equal depth, which moves a MAGNET network's permeability by up to a few percent.

Reading the result

  • Settings set the pore count. The headline counts every pore, boundary pores included. With SNOW2, a larger \(r_\text{max}\) or \(\sigma\) gives fewer, larger pores, so compare counts only between networks extracted with the same method, settings and voxel size.
  • Coordination number. The mean number of throats per pore is \(2 \times\) throats / pores, boundary pores and their throats included.
  • Check it before you use it. Run Network Validation and compare its permeability and diffusivity with the image-based values.

References


  1. J. T. Gostick, "Versatile and efficient pore network extraction method using marker-based watershed segmentation," Physical Review E 96 (2017) 023307. doi:10.1103/PhysRevE.96.023307 ↩

  2. M. McKague, H. Fathiannasab, M. A. Sadeghi, J. T. Gostick, "MAGNET: Medial Axis Guided Network Extraction Tool," InterPore Journal 2 (2025) IPJ011225-7. doi:10.69631/g47x8w91 ↩

  3. J. T. Gostick et al., "PoreSpy: A Python toolkit for quantitative analysis of porous media images," Journal of Open Source Software 4 (2019) 1296. doi:10.21105/joss.01296 ↩