Skip to content

About

Per-groove tire tread depth from a single panning camera. Tracks the groove lips and the Tread Wear Indicator, then fits the parallax between them across the sweep to recover depth. Classical computer vision, no trained model or labeled data. Ships with a sample clip so the documented run reproduces after cloning.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Training-Free Tire Tread Depth Estimation from Monocular Video

A geometry-based pipeline for estimating per-groove tread depth from a monocular camera pan, without training a task-specific ML model.

Groove tracking across the pan

Four circumferential grooves tracked across a camera pan. Green = groove lips, re-fitted on every frame; blue = groove centerline (top-surface reference); red = tracked Tread Wear Indicator (TWI). The depth-related signal comes from the relative motion between the surface and TWI references.


Contents


The problem

Tread depth is a vertical measurement, but an RGB image records only a 2D projection. Manual gauges and dedicated profilometry solve that measurement directly; this project explores a complementary route for a setup that already captures a short camera pan across the tread.

The changing viewpoint provides roughly 120 observations per groove in this example. Combining those observations makes it possible to recover a small relative-motion signal and fit one depth-related parameter per groove. Capture calibration then maps that pixel-domain result to millimeters.

The goal is therefore straightforward: estimate per-groove tread depth from a monocular RGB video while keeping the method explicit, inspectable, and independent of task-specific model training.

The method tracks two features at different depths: the groove lips, which provide a reference for the tread surface, and a Tread Wear Indicator inside the groove. Their relative motion during the camera pan produces a parallax signal that can be fitted with a geometric model.

The prototype combines geometric detection, optical flow, template-based localization, and nonlinear least squares. It needs no pretrained depth model, labeled tire dataset, or offline training stage, and the estimation path is traceable from measured image displacement through the configured capture geometry. The central idea is to turn the changing viewpoint into the depth cue itself.

The idea: measure the slide, not the shadow

The cue used here is motion parallax. As the camera swings past the tire, features at different depths move differently in the image. The top of the tread and the TWI provide two trackable references separated in depth, so their relative image motion encodes groove depth under the specified capture geometry.

Instead of estimating depth from the appearance of a single frame, the pipeline asks: over the whole pan, how far does the tracked TWI move relative to the groove's top-surface reference?

The Tread Wear Indicator makes it practical

Tread Wear Indicators (TWI, or "wear bars") provide a distinct reference inside the principal grooves. Their configured height also provides the offset that converts the surface-to-TWI measurement into total groove depth. In this example, that height is set to 1.6 mm.

This makes the TWI useful in two ways:

  1. Tracking target — its raised surface is more visually distinct than the surrounding groove floor.
  2. Height reference — when its height is known for the tire being inspected, it can be added to the estimated surface-to-TWI depth.

The parallax signal, zoomed on one groove

The same groove at two points in the arc. Cyan = the groove centerline computed from its two lips; red = the tracked TWI reference. Their horizontal offset $D_x$ changes from +4 px before head-on to −10 px after it. The model fits this relative displacement over the full sequence.

The model

Let $D_x$ be the horizontal offset in the image, in pixels, between the groove's surface reference and the tracked TWI. Under a simplified pinhole model, let $\Delta d$ be the vertical separation between the tread surface and the top of the TWI. For viewing angle $\theta$, camera-to-surface distance $Z$, and focal length $f$ (in pixels), the small-depth approximation ($\Delta d \ll Z$) gives:

$$D_x(\theta) = \frac{f}{Z} , \Delta d , \sin\theta$$

With a camera orbiting at a constant angular rate $\omega$, the viewing angle is linear in the frame index, $\theta = \omega,(t - t_0)$, where $t_0$ is the head-on frame. So the per-frame measurement

$$D_x(t) = x_{\text{surf}}(t) - x_{\text{twi}}(t)$$

should trace a sine wave in time:

$$D_x(t) = A \cdot \sin\big(\omega (t - t_0)\big) + C$$

  • $A$ — fitted parallax amplitude in pixels. Under the model assumptions, it is proportional to the surface-to-TWI depth.
  • $C$ — a groove-specific baseline offset that absorbs alignment differences, including the transverse angle of outer grooves on the curved (toroidal) tread.
  • $\omega,\ t_0$ — the camera's angular rate and the head-on frame. Both are capture parameters (see Calibration and outputs).

Fitting the whole time series for $A$ instead of differencing two frames combines roughly 120 noisy measurements in a single least-squares estimate. Converting to millimeters needs a scale constant $S = Z/f$ (mm/px):

$$d_{\text{groove}} = S \cdot |A| + h_{\text{TWI}}, \qquad h_{\text{TWI}} = 1.6\ \text{mm in this example}$$

Capture model

The derivation is designed for a controlled camera pan with the following geometry:

  • The tire remains static while the camera moves.
  • The sweep passes through head-on at a roughly constant angular rate.
  • Camera-to-tread distance $Z$ stays approximately constant across the arc.
  • Pinhole projection and the small-depth regime $\Delta d \ll Z$ are good approximations.
  • Each measured groove has two visible lips, is approximately circumferential, and is within the detector's ±45° head-on orientation tolerance.
  • Each measured groove contains a visible TWI with a known height.
  • Rolling-shutter skew is negligible at the selected sweep speed.
  • Lighting remains stable enough for optical-flow and template tracking.

Scale and camera motion are capture-calibration inputs; Calibration and outputs shows how they connect the image measurements to metric depth.

Why the TWI is the second depth reference

The two groove lips define the tread-surface reference. A TWI provides a second, trackable plane inside the groove, so the estimator can use their relative motion without requiring a cross-sectional model of the tire mold. A mold-specific model could instead infer depth from tapered groove width; the TWI route keeps the measurement tied to two directly tracked image features and a configurable wear-bar height.

How the pipeline works

Stage Module What happens
A frame_extractor.py Decode the video, sample every N-th frame, convert to grayscale, crop to the tread ROI.
B groove_detector.py On the head-on frame only: find the groove lip pairs geometrically.
C lip_tracker.py Propagate those lips through time with Lucas–Kanade optical flow; fit a curve to each lip per frame.
D twi_tracker.py Locate each TWI by template matching on the head-on frame, then track it with a MIL tracker.
E pipeline.py Extract $D_x$ per frame, apply temporal position gates, render debug overlays.
F depth_estimator.py Apply the IQR gate, fit the sine model for $A$, convert to millimeters.

A. Sampling and ROI. Frames are decoded, sampled at a fixed step, grayscaled and cropped to a rectangle over the tread face. Working on a crop keeps the 1D intensity profiles meaningful and keeps the run fast.

B. Head-on initialization — geometry, once. Full geometric detection runs on the frame where the camera is closest to perpendicular and the groove edges are clearest. The resulting geometry initializes both forward and backward tracking through the sequence:

  1. Band isolation — only a narrow horizontal band through the vertical center of the ROI is used, which limits the effect of distortion near the top and bottom of a wide-angle frame.
  2. Canny + probabilistic Hough (cv2.HoughLinesP) with a generous ±45° tolerance, so diagonal and oriented tread patterns still register as "vertical" groove edges. Segment x-positions are then clustered.
  3. Rotation-invariant polarity check — to decide whether an edge is a left lip (bright surface → dark groove) or a right lip (dark → bright), the detector samples pixels on either side of each clustered x-position at the band center. This keeps the check orientation-agnostic for diagonal edges.
  4. Surface thresholding — a likely lip should border the brighter top surface, so each candidate is required to be at least 75% as bright as the tread surface (estimated as the 75th percentile of the intensity profile) on its outer side. This helps reject internal shadows and bright bumps inside the groove.
  5. Pairing — left and right lips are matched under min/max width constraints to reduce pairing across adjacent grooves; if too many candidates survive, the strongest by combined edge prominence are kept.

C. Temporal lip tracking. For each lip, five tracking points are spread across the central 80% of the ROI and pushed through the sequence with pyramidal Lucas–Kanade (cv2.calcOpticalFlowPyrLK), both forward and backward from the head-on frame, so error accumulates outward from the best-conditioned frame instead of from one end of the clip. The current curve uses LK-valid points, while previous point locations remain as tracker state for the next update.

Because a tire is toroidal and the lens is wide, the grooves are visibly curved in the image — they are not straight lines. So each lip is re-fitted every frame as a second-degree polynomial $x = a y^2 + b y + c$ over its tracked points.

D. TWI localization and tracking. The TWI in each groove is found on the head-on frame by normalized cross-correlation (cv2.matchTemplate) against a small template crop. The search is masked to that groove's lip interval, preserving groove identity. From there each TWI is tracked with cv2.TrackerMIL, again forward and backward from the head-on frame.

E. Parallax extraction at matched height. The grooves are slanted and curved, so comparing a surface midpoint taken at the top of the ROI against a TWI sitting 300 px lower injects a large artificial offset that has nothing to do with depth. Instead, for every frame the tracked TWI's own $y$ is read off, both lip polynomials are evaluated at that exact $y$, and the surface reference is their midpoint:

$$x_{\text{surf}} = \tfrac{1}{2}\big(\text{left}(y_{\text{twi}}) + \text{right}(y_{\text{twi}})\big), \qquad D_x = x_{\text{surf}} - x_{\text{twi}}$$

F. Robust frame selection. Before fitting, the pipeline applies a median/MAD gate to the tracked surface and TWI positions, followed by an interquartile-range gate on $D_x$. The resulting fit uses 80–93% of the sampled frames per groove in this example.

G. Fit and conversion. scipy.optimize.curve_fit solves for $A$ and $C$; the residual standard deviation is reported as a fit-quality diagnostic, and $d_{\text{groove}} = S|A| + h_{\text{TWI}}$ gives the estimated depth. The generated diagnostic figure includes one subplot per groove with the retained measurements and fitted curve.

Example result

Input. A 17.9 s, 1620×1080 @ 30 fps camera pan of a stationary tire on a shop lift. The pipeline uses a 570×400 px ROI over the tread and samples every third frame in the configured 0–380 window: 127 frames, from index 0 through 378.

The input clip, sampled across its full length

The clip sampled every ~2.5 s. The camera moves from an oblique view on one side, through head-on around frame 190, to an oblique view from the other. The change in viewpoint provides the parallax cue.

The tread ROI across the arc

The fixed tread ROI (red) at the start, middle and end of the processed window. It has to contain all four grooves across the whole sweep, which is exactly what src/debug_roi.py is for.

Result scope. In the following table, parallax, residuals, and R² come directly from the tracked footage. The millimeter column applies the documented example calibration. All four grooves produce coherent fits with sub-pixel residuals:

Groove Estimated depth (mm) Fit residual (px) R² of sine fit Frames used
tread_1 (shoulder) 5.8 0.5 0.981 115 / 127
tread_2 6.4 0.6 0.983 118 / 127
tread_3 6.2 0.9 0.955 108 / 127
tread_4 (shoulder) 5.3 0.6 0.962 102 / 127

This run uses $S = 0.20$ mm/px and a 60° source-video arc; see Calibration and outputs. Stdout reports depth and fit residual, while R² is computed for the diagnostic figure. The run takes about 20 seconds on a laptop CPU without a GPU.

Per-groove parallax fits

Per-groove diagnostics regenerated as outputs/debug_fit.png: $D_x$ after temporal position gating in blue, points retained after the IQR gate in orange, the fitted parallax model in red, and a linear fit in gray for comparison.

What the numbers show. The fitted parallax amplitudes span 18–24 px, and all four grooves track the physical model closely: R² is 0.955–0.983, residual scatter is 0.5–0.9 px, and each fit retains 80–93% of the sampled frames. Under the example calibration, the pipeline produces per-groove estimates of 5.3–6.4 mm in a single CPU run.

Calibration and outputs

The implementation separates video-derived measurements from capture-specific inputs. Tracking and model fitting recover the parallax signal from the clip; calibration supplies the geometry needed for metric conversion. This keeps the estimator reusable across capture setups without retraining.

Role Quantity How it is supplied
Video measurement Relative parallax $D_x(t)$ per groove Computed from the tracked surface and TWI positions.
Model output Amplitude $A$, offset $C$, residual, R² $A$ and $C$ come from least-squares fitting; the retained series and fitted curve provide the diagnostics.
Capture calibration Scale $S = Z/f$ (mm/px) From camera intrinsics and working distance, or from a known tread-plane dimension. Example setting: 0.20 mm/px.
Motion calibration Source-video arc / $\omega$ From a fixed-rig sweep rate, encoder, IMU, or visual ego-motion. Example setting: 60° across the full source video.
Tire input TWI height $h_{\text{TWI}}$ From the tire specification. Example setting: 1.6 mm.
Sequence reference Head-on frame $t_0$ Selected from the clip or supplied by a fixed rig. Example setting: frame 190.

For the documented clip, scale and source-video arc are example configuration values rather than measurements recovered from the footage. In a calibrated capture, those same fields hold measured rig values; the tracking and estimation code is unchanged.

Why a training-free approach

This prototype uses an explicit projective-geometry model rather than a learned depth predictor. The relationship between observed motion and reported depth stays inspectable: each result includes the fitted amplitude, residual scatter, and a per-frame diagnostic plot.

The implementation runs on a CPU with OpenCV, NumPy, SciPy, and Matplotlib. It includes no pretrained depth weights, labeled-data requirement, or offline training pipeline. Capture-specific geometry is represented explicitly in Config: adapting the pipeline means setting the ROI, head-on frame, groove count, TWI template, scale, and camera arc rather than collecting data and retraining a model.

Where this approach fits

Several methods can contribute to tread-depth measurement. This qualitative design comparison shows the role each one naturally serves; it is not a measured benchmark.

Approach Strong fit when Role in this design space
Parallax + TWI (this project) A calibrated RGB sweep and visible TWI are available Produces explicit per-groove geometry without task-specific training data.
SfM / multi-view triangulation Surface texture supports stable correspondence across views Reconstructs broader 3D structure, followed by a metric-scale step.
Monocular depth networks A suitable target-domain model and metric anchor are available Provides dense, single-frame depth inference.
Supervised regression (image → mm) Representative gauge-labeled data cover the intended tires and camera setups Learns a direct task-specific mapping from appearance to depth.
Structured light / laser triangulation Dedicated calibrated hardware is part of the inspection station Measures a direct tread profile with active illumination.
Occlusion geometry A wide, controlled sweep produces a clear visibility boundary at the groove floor Offers a compact geometric cue for compatible captures.

Running the code

Requirements

  • Python 3.10+ (the code uses PEP 604 type unions)
  • opencv-python, numpy, scipy, matplotlib — all in requirements.txt

Verified on Python 3.13 with OpenCV 4.12, NumPy 2.2, SciPy 1.16, Matplotlib 3.10. CPU only; no GPU or external model weights are used.

pip install -r requirements.txt

Input video

The sample clip used throughout this README ships with the repository at assets/tire_pan_sample.mp4, so the documented run works straight after cloning. To use your own footage, point Config.video_path at it:

# config.py
video_path: str = "assets/my_tire_pan.mp4"

Run

All asset paths in config.py are relative to the project root, so run from there:

# optional: check that the ROI covers the tread across the whole pan
python src/debug_roi.py

# full pipeline
python src/pipeline.py

Outputs

Everything generated at run time lands in outputs/:

Output Where
Depth table for every groove, with fit residuals stdout
Per-groove parallax scatter + fitted model outputs/debug_fit.png
Per-frame tracking overlays (lips, centerline, TWI, median/MAD-rejected tracks in magenta) outputs/frames/
ROI preview frames outputs/debug_roi_*.png
Tire Tread Depth Estimation Results (TWI Tracking)
Scale assumption : S = 0.2 mm/px (Z~350mm, f~1750px)
TWI Height offset: 1.6 mm
Orbital arc      : 60.0 deg (assumed)
Head-on frame    : 190
-----------------------------------------------
Groove    Depth (mm)    Fit residual (px)
-----------------------------------------------
tread_1   5.8           0.5
tread_2   6.4           0.6
tread_3   6.2           0.9
tread_4   5.3           0.6
-----------------------------------------------

Repository layout

.
├── README.md
├── config.py                  # every tunable parameter, one dataclass
├── requirements.txt
├── src/
│   ├── pipeline.py            # orchestrator: run this
│   ├── frame_extractor.py     # decode, sample, grayscale, ROI crop
│   ├── groove_detector.py     # head-on lip detection (Canny + Hough + polarity)
│   ├── lip_tracker.py         # Lucas–Kanade lip tracking + per-frame curve fit
│   ├── twi_tracker.py         # TWI template match + MIL tracking
│   ├── depth_estimator.py     # IQR filter, sine fit, px → mm
│   └── debug_roi.py           # ROI preview utility
├── assets/                    # static files only
│   ├── tire_pan_sample.mp4    # sample clip the documented example runs on
│   ├── twi_template.png       # TWI crop used for template matching
│   ├── debug_fit.png          # committed snapshot of the fits, shown above
│   └── fig_*.{png,jpg}        # figures used in this README
└── outputs/                   # everything a run generates (created on demand, gitignored)
    ├── debug_fit.png
    ├── debug_roi_*.png
    └── frames/

Roadmap

The current implementation establishes the full path from a tracked monocular video to per-groove estimates and fit diagnostics. Further work can build validation, repeatability, and broader capture support around that core:

  • Gauge-labeled evaluation — pair video runs with measurements across multiple tires, tread patterns, wear states, and capture conditions, then report absolute-error and repeatability distributions.
  • Rendered end-to-end fixture — use known 3D geometry and camera motion to exercise groove detection, lip tracking, TWI matching, and estimation in one automated test.
  • Broader capture coverage — validate the configuration workflow across tread patterns, camera geometries, and sweep speeds beyond the bundled example.
  • Automatic setup — derive the tread ROI, groove count, and head-on frame from the sequence.
  • Multi-reference TWI tracking — initialize several in-groove references and combine consistent tracks robustly.
  • Generalized groove extraction — support additional tread geometries beyond approximately circumferential grooves.
  • Measured ego-motion — use an encoder, IMU, or background feature tracks so $D_x$ is fit against measured viewing angle instead of frame index.
  • Capture characterization — quantify rolling-shutter effects across sweep speeds and select the appropriate sensor or motion profile.

About

Per-groove tire tread depth from a single panning camera. Tracks the groove lips and the Tread Wear Indicator, then fits the parallax between them across the sweep to recover depth. Classical computer vision, no trained model or labeled data. Ships with a sample clip so the documented run reproduces after cloning.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages