AI Fracture Mapping
VRGS can extract fracture traces directly from an outcrop photograph using a deep-learning detector, turn the detected pixels into clean centre-line polylines, project those onto the 3D model, and feed them to the Discrete Fracture Network (DFN) tools as virtual orientation measurements.
The whole pipeline runs in the Photograph view and is designed to be a few clicks end-to-end, with a small set of settings to tune for your imagery.
Photograph ──► Fracture AI (U-Net) ──► probability heatmap
└─► Extract Fracture Lines (2D) ──► clean 2D traces (skeleton → join → simplify)
└─► Map Fracture Lines to 3D ─────► 3D polylines on the DOM
└─► Estimate Orientations ────────► virtual dip/azimuth → DFN
The AI detector is one of three ways to produce the probability/edge map that feeds the vectorizer. The other two are Ant Colony Optimisation (ACO) and the Phase Congruence detector (documented at the end of this page). Once a map exists, the Extract → Join → Map to 3D steps are identical regardless of how it was produced.
The workflow
Open a calibrated photograph (an SfM image with a recovered camera, or a photo registered to the model) in the Photograph view. Most commands below are on the right-click context menu of the photo, under the fracture/AI sub-menu; the tuning sliders are in the Polyline Settings property pane.
1. Detect — Fracture AI
Run the AI detector — the Fracture button on the image-tools ribbon. This executes the bundled U-Net (ResNet-34 backbone) over the photograph and produces a per-pixel fracture probability map in the range 0–1. The map is shown as a colour overlay (bright yellow → red) on the image.
- The model tiles the image at 224×224 with 25 % overlap and blends the tiles, so there are no seams. It uses the GPU (CUDA) when available and falls back to the CPU automatically.
- The detection threshold is the colour-map filter minimum, set to 0.5 when detection runs. Pixels above it are treated as fracture; you can raise or lower it in the colour-map properties pane to make detection stricter or more inclusive (see Detection threshold).
Enable Auto-extract fracture lines (2D) in the colour-map panel to have step 2 run automatically as soon as detection finishes.
2. Extract Fracture Lines (2D)
Right-click → Extract Fracture Lines (2D). This converts the probability map into clean 2D polylines, in four stages:
- Binarize the probability map at the detection threshold — optionally with hysteresis (seed-and-grow) so a real fracture is not chopped wherever its probability dips (see Hysteresis thresholding).
- Skeletonize and trace — the binary mask is thinned to a one-pixel centre-line and traced as a graph: the tracer classifies endpoint, path and junction pixels and links arms straight through each junction by orientation continuity, so a fracture stays continuous across a
+/T/X crossing instead of being split into stubs (a+becomes two through-traces, not four). - Join short fragments end-to-end into longer traces (see Joining).
- Simplify the vertices with Douglas-Peucker, then join once more on the simplified lines (simplification straightens the staircased skeleton, which lets a few more collinear fragments line up).
The result is drawn on the image as an editable 2D trace preview (orange by default). Nothing has been committed to the 3D model yet — review and edit first.
3. Review and edit the 2D traces
Before projecting, you can clean up the preview:
- Segment Rose Diagram (right-click → Show Segment Rose Diagram): a length-weighted rose of trace directions appears top-right. Drag a wedge to keep only traces in a direction band; click the centre to clear. A length histogram below it lets you drag to drop traces shorter than a minimum. Both filters apply when you map to 3D.
- 2D line-edit tools (image-tools ribbon): select, erase line, erase vertex, join selected, split, move vertex, insert vertex, and extend. Use these to merge a trace the auto-join missed, cut one that wrongly bridged two fractures, or nudge a vertex.
4. Map Fracture Lines to 3D
Right-click → Map Fracture Lines to 3D, choosing the output type:
- (Polylines) — each 2D vertex is ray-cast through the calibrated camera onto the model surface, producing 3D polylines in a new group named
ACO_<photo>. Traces whose vertices mostly miss the model geometry are dropped. - (Orientations) — the same reprojection, but each trace becomes a single virtual orientation measurement: a plane is fitted through the trace's 3D points and its normal gives the dip/azimuth directly (true dip where the outcrop has relief — see the note on true vs apparent dip). The measurements land in a new orientation group, coloured by quality, ready to feed the DFN without an intermediate polyline step.
This is the heavy step (one ray-cast per vertex), which is why detection/extraction (instant) and projection (slower) are separate commands.
5. Estimate orientations and build a DFN
In the interpretation/DFN tree, select the outcrop mesh together with the trace group (or the individual traces) and run Estimate Orientations. For each trace VRGS fits a plane through the reprojected 3D points: where the outcrop has enough relief that the trace bends out of a straight line, the best-fit plane normal gives the true dip directly; where the trace is near-straight (a flat face), it falls back to trace tangent × outcrop normal, an apparent dip (see the note below). Results are grouped as "Virtual orientations from <mesh>", the summary reports how many were true vs apparent, and they behave like any other orientation measurement feeding the DFN size/intensity workflow.
Each virtual orientation also gets a quality score (0–1) blending the detector's mean confidence along the trace with the reliability of the orientation method: a well-conditioned best-fit plane (true dip) scores highest, an apparent-dip fallback lower, and a 2-point chord lowest. Orientations are coloured red (low) → green (high), the quality range is reported in the result summary, and the score is appended to each label (q=…), so you can spot and weed out unreliable measurements before fitting set statistics.
The same traces can also drive Override P32 from Traces and Score Against Traces in the DFN tools. See the DFN user guide and DFN interpretation matching.
True vs apparent dip
Every point of a trace lies on the fracture plane, so fitting a plane through the reprojected 3D trace recovers the true fracture orientation when the outcrop has relief along the trace — the relief makes the trace bend out of a straight line and span the plane in two dimensions, which pins the plane down. This is what both Map → Orientations and Estimate Orientations do.
On a flat outcrop face the trace is a straight line, which cannot constrain a unique plane; VRGS then falls back to an apparent dip that assumes the fracture is locally perpendicular to the outcrop. So:
- Longer traces over varied topography give the most reliable true dips (low
condition_score→ high quality, green). - Near-straight traces on flat faces come out as apparent dip (flagged lower quality) — treat them with caution, or capture the same fracture on two non-coplanar faces to recover its true orientation.
Settings reference
The fracture settings live in two places: checkable toggles on the photo's right-click menu, and sliders in the Polyline Settings property pane. Re-run Extract Fracture Lines (2D) after changing any of them.
Detection threshold
- What: the colour-map filter minimum — the probability above which a pixel is fracture. Set to 0.5 by Fracture AI.
- Lower (0.3–0.45): catches faint / thin fractures, at the cost of more speckle and false positives.
- Higher (0.55–0.7): keeps only confident detections; cleaner but may break faint traces into fragments (which the join step then has to bridge).
- Adjust it in the colour-map properties pane; the overlay updates so you can see exactly what will be vectorized.
Hysteresis thresholding
Right-click → Hysteresis Thresholding (reduce fragmentation) (on by default).
Instead of a single hard cut, the mask is seeded at the detection threshold and then grown into connected neighbouring pixels down to a lower band. A real fracture that momentarily dips below threshold (a thin spot, shadow or lichen) stays connected, so it is not split into fragments — while isolated weak speckle, having no strong seed to grow from, is still rejected.
- Hysteresis low band (% of threshold) (Polyline Settings, default 60): how far below the seed threshold the grow band reaches. 60 % of a 0.5 threshold grows down to 0.3.
- Lower (40–50 %): bridges deeper dips — more aggressive reconnection.
- Higher (70–90 %): conservative; only very shallow dips are bridged.
Hysteresis only helps where a fracture's probability dips (stays partly elevated across the gap). Where the model produced essentially nothing across a gap, use the join step instead — it bridges on geometry, not probability.
Joining fragments into traces
Right-click → Auto-join Fragments on Extract (on by default) runs the joiner during extraction; Join Fracture Segments runs it on demand on the current preview.
The joiner links two fragment endpoints into one trace only when all three geometric tests pass, and it iterates to convergence so long fractures chain across several gaps:
| Setting (Polyline Settings) | Default | Meaning |
|---|---|---|
| Join max gap (1/1000 of diagonal) | 25 | Largest endpoint gap to bridge, as a fraction of the image diagonal. Auto-scales with photo resolution — 25 ≈ 2.5 % of the diagonal, about 125 px on a 4000×3000 photo. This is the main consolidation knob. |
| Join max orientation diff (deg) | 25 | The two fragments must trend the same way (axial difference of their end-directions). |
| Join max kink (deg) | 30 | The gap must be a continuation, not a sideways offset — the bridge must be near-collinear with each fragment's end-direction. This is what rejects parallel traces lying close together. |
End-directions are estimated by a short PCA line-fit at each trace end, which averages out skeleton staircasing so short noisy fragments still match correctly. The gap is resolution-relative (a fraction of the image diagonal), so the same setting works across photos of different sizes.
- Want fewer, longer traces? Raise Join max gap. Loosen orientation (e.g. to 30–35°) if fragments of one fracture are being left split.
- Traces wrongly bridging separate fractures? Lower Join max gap, tighten orientation / kink.
Joining is non-destructive and re-tunable: change a join slider and run Join Fracture Segments again — the result is recomputed from the original extracted fragments, not joined on top of the previous result. (This discards manual line edits, so do your manual clean-up after you have settled the join settings.)
Simplification (Douglas-Peucker)
- Simplification value (Polyline Settings, default 5): the Douglas-Peucker tolerance in pixels — how far a vertex may be dropped from the line it sits on. Higher values give fewer vertices (and fewer, faster ray-casts when mapping to 3D).
- Decimation never reduces a trace below three vertices, so every projected trace retains enough shape to define a stable orientation rather than collapsing to a single straight chord.
Minimum trace length
- Min Polyline Length (ACO/extractor settings, default 5 px): traces shorter than this after vectorization are discarded as noise. Raise it to suppress short speckle; lower it to keep small fractures.
Tuning recipes
| Goal | Do this |
|---|---|
| Too many short fragments | Keep Hysteresis on; lower its low band to ~50 %. Keep Auto-join on and raise Join max gap. |
| Long fractures left broken | Raise Join max gap; loosen Join max orientation to ~30–35°. |
| Different fractures merged together | Lower Join max gap; tighten orientation and kink. |
| Faint fractures missed | Lower the detection threshold (0.35–0.45); lower the hysteresis low band. |
| Speckle / false traces | Raise the detection threshold; raise Min Polyline Length. |
| Mapping to 3D is slow | Raise Simplification value; raise Min Polyline Length (both reduce vertex / trace counts). |
Diagnostics
When VRGS runs with the VRGS_BUILD_PATH environment variable set, every extract and join writes a one-line summary to logs/vrgs-debug.log (and the in-app message panel). These tell you exactly what each setting did:
Build traces: hysteresis=on (seed 0.500, low 0.300), join=on; 1407 raw -> 766 line(s); ...
Join detail: pairs=... rejected(gap=... orient=... kink=...) candidates=... accepted=... [gap=25/1000 diag = 125px, ...]
raw -> N line(s)is the consolidation: how many fragments the extract produced versus how many traces survive after joining.- The
Join detailline shows why candidate joins were rejected. Ifgap=dominates, raise Join max gap; iforient=orkink=dominate, loosen those tolerances; the resolved pixel gap is shown so you can sanity-check it against your image.
Classical detector: Phase Congruence
The Phase Congruence detector is an alternative, non-AI way to produce the fracture mask that feeds the same Extract → Join → Map to 3D pipeline. It is illumination- and contrast-invariant and works well on textured rock. Run it from right-click → Detect Fractures (Phase Congruence); the parameters below are in its settings pane (prefixed fd_ internally).
Core parameters
| Parameter | Default | Range | What it controls |
|---|---|---|---|
| Scales | 4 | 2–8 | Number of scale levels for multi-scale detection. Higher = wider range of feature sizes, slower. |
| Orientations | 8 | 4–16 | Orientation filters across 180°. Higher = finer angular discrimination, better for curved features. |
| Min Wavelength | 3.0 px | 2–10 | Smallest feature size detected. Higher = ignores fine detail, more noise-resistant. |
| Scale multiplication factor | 2.1 | 1.5–3.0 | Size ratio between successive scales. Lower = denser coverage, slower. |
| Sigma/F | 0.65 | 0.4–1.0 | Log-Gabor frequency bandwidth. Lower = sharper/selective; higher = more complete but less selective. |
| Angular spread | 15.0° | 5–45 | Angular tolerance per orientation filter. Higher = better edge continuity on curves. |
Additional threshold (fd_nms_thresh_) | 0.0 | 0.0–0.3 | Extra suppression after automatic (Otsu) thresholding. Raise to clean up weak responses. |
Auto-run (fd_auto_run_) | false | — | Re-detect automatically when a parameter changes (handy while tuning). |
Presets
| Scales | Orient. | Min λ | Mult | Sigma/F | Ang. spread | Extra thr | |
|---|---|---|---|---|---|---|---|
| Clear / high-contrast | 3 | 8 | 3.0 | 2.5 | 0.55 | 10° | 0.0 |
| Natural / textured | 5 | 12 | 4.0 | 2.1 | 0.75 | 20° | 0.05 |
| Fast | 3 | 6 | 5.0 | 2.5 | 0.65 | 15° | 0.0 |
| Maximum quality | 6 | 16 | 3.0 | 1.8 | 0.65 | 15° | 0.0 |
Quick tuning
- Too many false detections: raise Additional threshold (0.05–0.1) or Min Wavelength.
- Missing weak edges: set Additional threshold to 0; raise Sigma/F.
- Fragmented edges: raise Angular spread (20–30°), or lower Orientations.
- Too slow: lower Scales (2–3) and Orientations (4–6); raise Min Wavelength and Mult.
After detection, vectorize and map to 3D exactly as in steps 2–5 above. Note that, unlike the AI path, the classical mask can also be turned into 3D contours directly with Convert Mask to 3D (Contours).
Related pages
- Ant Colony Optimisation (ACO) — swarm-based feature extraction, an alternative mask source.
- Auto Structural Mapping
- DFN user guide and DFN interpretation matching — using the mapped traces to build and constrain a discrete fracture network.