Skip to main content

Case Study

Picking Sinusoids Without Labels: An Unsupervised Hough + DBSCAN First-Pass for Bedding Detection

Before a single labelled sinusoid existed, a classical-CV pipeline — Canny + probabilistic Hough at threshold 30, then DBSCAN swept across more than 10,000 parameter combinations — recovered bedding traces and clustered four stratigraphic zones, giving the operator a baseline it could trust ahead of the supervised models.

Case study

The honest way to start an AI engagement on borehole image logs is to admit you have no labels. When we began with a mid-sized Middle East carbonate operator, there was no annotated corpus of bedding planes, no validated dip-and-azimuth picks at scale, nothing a supervised model could learn from. What there was, on disk, was a stack of high-resolution borehole image logs from two different microresistivity imaging tools — and a hard question from the operator's geoscience team: before we trust a transformer you have not built yet, can you recover bedding from these images at all, with a method we can read line by line?

That constraint shaped Phase 1. We deliberately did not reach for deep learning. We built an unsupervised, classical computer-vision pipeline — edge detection, a probabilistic Hough transform, and density-based clustering — whose every step is inspectable, whose parameters are auditable, and whose output is a first-pass bedding interpretation that needs no ground truth to produce. It became the baseline the operator could trust, and the yardstick every later supervised model had to beat.

Why a planar feature becomes a sinusoid

The geometry is the whole reason this problem is tractable without labels. A bedding plane or a fracture is a flat surface in three dimensions. Where that plane cuts the cylindrical borehole, the intersection is an ellipse. Unwrap the cylinder wall into a flat 2D image — which is exactly what a high-resolution microresistivity imaging tool produces, a resistivity image indexed by depth on one axis and azimuth (0–360°) on the other — and that ellipse projects to a sine curve. The amplitude of the sinusoid encodes the dip of the plane; the phase encodes its azimuth. Formally, the trace follows tg = tan(dip)·sin(x + azimuth), and we fit each pick with A·sin(ωx + φ) + offset, where A carries dip and φ carries azimuth.

IMAGE-LOG GEOMETRY · SCHEMATIC38° / 120°dip steepness · dip azimuthy = A·sin(0.0175·x + φ) + offsetTilt the plane — the cut becomes a sinusoidAmplitude A carries dip steepness; phase φ carries azimuth — the trough points down-dip.plane cut · sinusoid (A = dip)trough = down-dip azimuth (φ)BOREHOLE · A FLAT PLANE CUTS THE CYLINDERN · cutUNROLLED IMAGE · x = AZIMUTH 0–360°, y = DEPTH0°90°180°270°360°Atrough @ 120°DIP 38° · steeper → taller A (25%, schematic)0°30°60°90°AZIMUTH 120°rotates φ — trough swings to thedown-dip compass bearingNSchematic: dip 0–90° & azimuth 0–360° are generic axes, not a well · A=dip, trough φ=azimuth exact
Why every planar feature on an image log is a sinusoid — and how the curve encodes dip and azimuth. A flat plane (bed, fracture, fault) cuts the borehole cylinder on the left; unroll the cylinder against an azimuth axis (0–360°) and the intersection becomes a sine curve on the right. Drag the dip slider and the curve's amplitude A grows as the plane tilts steeper; turn the azimuth knob and the orange trough — the down-dip point — rotates around the borehole, sliding the curve's phase φ. This is the article's own fitting form y = A·sin(0.0175·x + φ) + offset: A carries dip, φ carries azimuth. Pure explainer geometry — dip 0–90° and azimuth 0–360° are generic axis ranges, not client data; the amplitude-to-dip mapping is held in frame near 90° and is labelled schematic.

That mapping is the engineering gift the physics hands you: you never have to recognise a "bedding plane" as a semantic object. You only have to find sinusoids in an image and read off two numbers. Everything downstream — edge detection, line voting, clustering — is in service of locating those sinusoidal traces robustly in noisy, partially-blind imagery.

The data engineering nobody sees

Before any computer vision runs, the image has to be made trustworthy, and on raw borehole logs that is most of the work. We read the binary wireline log files with dlisio, extracting the dynamic and static image channels. Two facts about this data dictated the entire preprocessing layer.

First, the logs are not complete. Pad geometry means an image tool images up to roughly 80% of the borehole wall; the rest is unmeasured. Those gaps arrive coded as a sentinel (−9999) that, left untouched, masquerades as a real resistivity value and poisons every edge detector downstream. We mapped the sentinel to NaN and handled it explicitly rather than letting it leak into the gradient computation.

Second, resolution sets a hard floor on what any method — classical or deep — can ever claim. One pixel of the image-log raster corresponds to about 3 cm of depth. That is a permanent ±3 cm depth uncertainty baked into the instrument, before any algorithm touches the data. We stated it up front to the operator, because a first-pass method that quietly implies sub-centimetre depth precision is not a baseline you can trust — it is a baseline that will embarrass you at validation. The static image was rescaled to a 0–255 intensity range, and a median blur (kernel size 5) suppressed salt-and-pepper noise without smearing the thin, low-contrast bedding edges we needed to keep.

The baseline's job is to be honest, not impressive

A first-pass interpretation that overstates its own precision is worse than no baseline at all — it sets a bar the supervised model "beats" only on paper. We anchored Phase 1 to the instrument's real limits: ~80% borehole coverage, a −9999 no-data sentinel, and ±3 cm depth resolution from the 1-pixel-equals-3-cm scale.

Step one: Canny edges and a probabilistic Hough vote

With a clean, range-normalised image, the first vision stage finds candidate edges and votes them into line segments. We ran Canny edge detection with hysteresis thresholds of 200 and 255 and an aperture size of 7 — tuned wide, because a steeply-dipping bedding trace in a carbonate is faint and discontinuous, and an over-eager edge map is easier to clean than a missing edge is to invent.

The edge map then feeds a probabilistic Hough transform (HoughLinesP), the engine that turns scattered edge pixels into oriented line segments by accumulator voting. The parameters are the design decision that matters here: distance resolution rho = 1 pixel, angular resolution theta = π/180 (one degree), an accumulator threshold of 30 votes to confirm a segment, a minimum line length of 30 pixels, and a maximum gap of 5 pixels to bridge. The threshold of 30 is the crux. Set it high and you only recover the boldest, most continuous traces and miss real bedding; set it low and the image fills with spurious votes from texture and tool artefacts. Thirty was the operating point where a human interpreter, looking over our shoulder, agreed the recovered segments corresponded to traces they would have drawn.

This is, deliberately, a pipeline with no learned weights. Every output is a deterministic function of the input and a handful of named constants. For a first engagement, on an operator's confidential reservoir, that auditability was worth more than any accuracy a black box could have offered.

Step two: DBSCAN, and 10,000 parameter combinations

Hough gives you a cloud of short line segments. It does not give you which segments belong to the same sinusoid, and it does not give you stratigraphic structure. That grouping is a clustering problem, and the clustering is where the real model-development effort went.

We cast every detected point into a three-dimensional feature space chosen to match the geometry: X is the azimuth coordinate, bounded to [0, 359]; Y is the depth coordinate, running over the image height; and Z is the pixel intensity, bounded to [0, 255]. A sinusoid is then a coherent, density-connected ribbon through that (X, Y, Z) space, and DBSCAN — density-based clustering that needs no preset number of clusters and treats sparse points as noise — is the natural tool to recover it.

Natural, but not easy. DBSCAN's behaviour hinges on two parameters, eps (the neighbourhood radius) and min_samples (the density floor), and on this data the response surface was, in our notes at the time, very unstable: a small change in eps flipped a clean bedding ribbon into either one giant blob or a scatter of noise. There was no analytic shortcut. So we engineered a systematic sweep — more than 10,000 parameter combinations trained and scored — across eps, min_samples, and the candidate clustering thresholds (we tested 30, 45, 50, and 60), logging each run so the choice of operating point was evidence-driven rather than a lucky guess. This is the unglamorous core of unsupervised model development: when you have no labels to validate against, the search itself, exhaustively logged, is your validation discipline.

Step three: four zones the operator recognised

The payoff was structure. With the swept DBSCAN configuration, the clustered points resolved into four stratigraphic zones, each with a coherent dip-azimuth signature — boundaries that the operator's geoscientists could map onto the formation tops they already knew. A companion K = 4 clustering over the azimuth spectrum confirmed the split; tellingly, other values of K broke the sinusoid sections apart rather than cleaning them, which is itself a result — the data wanted four groups, and forcing more fractured real traces.

GEOBFDT · 14 WELLS · ONE FORWARD PASSDEPTHdetection axis · at 3 cm toleranceBELOW USEFULOne pass, three axes — depth is the binding constraint, not geometryPick an axis, step its tolerance: detection lags at a tight window; dip and azimuth are already strong.Depth (F1)Dip (acc.)Azimuth (acc.)Fracturesdetection65%Beddingsdetection63%useful regime≈70% · illustrativeTight window — marginal: below the useful bar.TOLERANCE3 cm3 cm4 cm5 cm← drag / arrow keys to step the depth windowSINGLEFORWARDPASSno masks,no sinusoidre-fittingF1 65/63 @3cm, 75/69 @5cm, 55 @4cm (frac, horizontal); dip 90 @3°; azimuth 92/84 @15° — the article's own · the ~70% useful-regime line is illustrative
GeoBFDT emits the whole (class, depth, dip, azimuth) tuple in one forward pass — but the three axes are not equally hard. Detection along the depth axis is the binding constraint: at a tight 3 cm window fracture F1 is only ~65% (beddings ~63%) and only clears the useful regime for structural work once tolerance loosens to 5 cm (~75% / ~69%); horizontal wells hold ~55% at 4 cm. The geometric axes the interpreter actually fits sinusoids for are already strong at tight tolerance — dip ~90% at 3°, azimuth ~92% (fractures) / ~84% (beddings) at 15°. Pick an axis and step its tolerance: depth is the lever you loosen, dip and azimuth are already past the line. All accuracies and tolerances are the article's own; the dashed ~70% 'useful regime' line is an illustrative reading aid (the article names no exact F1 cutoff).

We were equally clear about where the unsupervised method stopped. Dip and azimuth picks matched expert ground truth only when the sinusoid was continuous; where a trace was broken — by a vug, a washout, or a no-data gap — the Hough-plus-clustering stack would latch onto a fragment and report a confident but wrong plane. To keep the baseline trustworthy we enforced geometric sanity constraints on every accepted pick: a candidate sinusoid had to span a consistent depth interval and fit at least 50 supporting pixel points before it counted. Picks that failed were dropped rather than guessed, because a first-pass interpretation earns the operator's trust by what it refuses to claim as much as by what it finds.

From zero labels to a trusted, inspectable bedding pick

Before

No model, no baseline

No labelled sinusoids existed; a supervised model had nothing to learn from and nothing to be measured against

After

Auditable first-pass interpretation

Canny + HoughLinesP (thresh 30) + DBSCAN swept over >10,000 parameter sets → bedding traces clustered into 4 stratigraphic zones

Phase-1 baseline the operator could trust — and every later supervised model had to beat

Why this was the right first move

It would have been tempting to skip straight to a transformer. We did not, and the engagement was stronger for it — a discipline we have carried into work with operators across the Middle East and the United States, where the first deliverable that earns trust is rarely the fanciest one.

The unsupervised pipeline did three things no premature supervised model could. It produced labels-in-waiting: the clustered, geometry-constrained sinusoids became the seed annotations and the structural prior for the supervised dataset that followed. It set an honest accuracy floor — the continuous-sinusoid regime where classical CV already worked well, against which the supervised model's value could be measured precisely on the hard, discontinuous, overlapping cases. And it built operator trust through transparency: a geoscientist could read every threshold, re-run every step, and see exactly why the method drew a plane where it did.

The clean failure mode pointed directly at the next phase. Classical CV breaks where sinusoids overlap and where traces are discontinuous — precisely the regime that dominates a fractured carbonate, and precisely what a set-prediction model with bipartite matching is built to solve. The unsupervised baseline did not just buy time; it defined the problem the supervised pipeline was commissioned to attack.

What an unlabelled first-pass actually buys you

  1. With no labels, a classical-CV pipeline — Canny (200/255, aperture 7) + HoughLinesP at threshold 30 + DBSCAN — recovered bedding sinusoids and clustered four stratigraphic zones, giving the operator an auditable Phase-1 baseline before any supervised model existed.
  2. The model development was in the clustering: DBSCAN's eps/min_samples surface was very unstable, so we swept more than 10,000 parameter combinations and logged every run, making an exhaustive search the validation discipline that absent labels otherwise deny you.
  3. Honesty was the design constraint — ±3 cm depth resolution (1 pixel = 3 cm), ~80% borehole coverage, and a 50-pixel-support sanity gate kept the baseline from overstating itself; its clean failure on overlapping, discontinuous sinusoids defined the exact problem the later supervised DETR was built to solve.

References

  1. Suzuki & Abe (1985); Canny (1986); and the probabilistic Hough transform (Matas et al., 2000) — classical computer-vision primitives used for edge detection and line voting in the Phase-1 pipeline.

  2. Ester, Kriegel, Sander & Xu (1996). A Density-Based Algorithm for Discovering Clusters (DBSCAN). KDD 1996.

  3. Pipeline parameters, the >10,000-combination DBSCAN sweep, and the four-zone stratigraphic result derived from internal Phase-1 validation on a confidential Middle East carbonate borehole-image dataset acquired with two different microresistivity imaging tools; data and code withheld under operator confidentiality.

Go to Top

© 2026 Copyright. Earthscan