A camera that looks along a road at an angle maps the pavement onto the sensor as a trapezoid. Every detector you then run — Canny edges, Hough lines, a matched filter built for linear objects — finds the two slanted borders of that trapezoid and reports them as the longest, straightest cracks in the frame. Grayscale thresholding does not rescue you either, because dark asphalt and a dark crack sit within a few gray levels of each other. The fix is the order of operations: build a binary mask of the road surface first, pull it a few pixels inside its own border, then run crack detection only inside the mask. This walkthrough gives the pipeline, the numbers that place the mask boundaries, and the checks that prove the border is gone.
Mask the input, not the output
Resist deleting border detections after the detector runs. A crack that ends at the image edge and the trapezoid border itself produce the same detection geometry, so a distance-to-border rule throws away real cracks near the edge while keeping anything that straddles the line. Remove the border from the detector's input instead: a binary mask that covers the pavement and stops a few pixels short of the visible road edge. Nothing outside the mask is processed, so the border can never be found — and cracks right up to the erosion line survive.
The mask is also what makes a linear detector usable at all. A Hough line votes on any long, coherent gradient, and the road border outvotes every crack in the frame. For crack networks where line voting stops being the right model, read Hough line detection for cracks: when to switch to contour stats — but mask first either way.
The mask in three operations
Build the mask once, from a single reference frame:
A is the grayscale frame — convert color input to gray first. Each step earns its place:
-
imbinarize(A)thresholds the frame. Here you only need road-versus-not-road contrast — pavement against grass, soil or sky — which is far stronger than crack-versus-asphalt. A global cut that would fail for crack extraction usually separates the road cleanly. -
bwconvhulltakes the convex hull of the binary region. Dark cracks punch holes in a binarized road; the hull fills them, and the hull of a trapezoid-shaped region is the clean trapezoid the camera geometry promises. -
imerodewithstrel("disk", 3)pulls the boundary 3 px inward everywhere, past the gradient band that surrounds the visible border. Radius 3 px clears a 3×3 gradient kernel; use 5-10 px when the border is soft from focus loss or compression. - The finished mask multiplies the detector output — or the binarized crack image — frame after frame.
scikit-image's morphology module supplies the same pieces: threshold the frame, take the hull of the largest region, erode with a disk-shaped element of radius 3 px.
Step by step: from frame to masked detections
- Lock the camera down: rigid mount, focus and iris fixed, exposure and gain fixed once set. Any drift moves the trapezoid under a static mask.
- Capture one reference frame of empty pavement from the survey position.
- Convert to grayscale and binarize it. The road should separate from its surroundings in one global cut; it almost always does.
- Take the convex hull of the largest region. The result should be the trapezoid you see by eye. If it is not, a second pavement-like region is in frame — crop the input first.
- Erode the hull with a disk of radius 3 px, more if the border is soft.
- Trim the far edge of the mask where the lane gets too small for your target crack width. The next section puts numbers on that cut.
- Save the mask as a binary image and reuse it for every frame. With a fixed camera it does not change; remeasure only after someone touches the mount.
- Run detection and thresholding inside the mask, multiply the output by it, and report only what survives.
Worked example: the far edge of the mask on a 3.6 m lane
Inputs:
- Frame size: 4000 × 3000 px — the resolution on the camera card below.
- Lane width: 3.6 m, a standard highway lane.
- Mounting (example case): camera looking forward along the lane. At the bottom of the frame the lane spans the full 4000 px; at the top it spans 2000 px.
- Target: report cracks 3 mm and wider, using the pixel rule from camera resolution for defect detection — at least 3 px across the narrowest feature you must report.
- Bottom of frame: 3600 mm / 4000 px = 0.90 mm per px. A 3 mm crack spans 3 / 0.90 = 3.3 px — detected.
- Top of frame: 3600 mm / 2000 px = 1.80 mm per px. The same crack spans 1.7 px — missed.
- The 3-px rule needs a scale at or under 3 mm / 3 px = 1.0 mm per px, so the lane must still span 3600 mm / 1.0 mm = 3600 px.
Decision: set the far boundary of the mask at the row where the lane is still 3600 px wide — 90 % of the frame width in this mounting. Everything nearer runs at 0.90-1.00 mm per px and holds every 3 mm crack. Beyond that row the honest floor is 3 px at 1.0-1.8 mm per px, so cracks of 3.0-5.4 mm only. Do not extend the mask to the horizon: the detector will silently miss hairline cracks out there, and nothing in the output tells you which misses are real.
The camera behind these numbers:
The LS-CMR-0166 delivers 4000 × 3000 px at 30 fps over USB3, from a 1/1.7" rolling-shutter sensor.
- Sensor format
- 1/1.7"
- Interface
- USB3
- Resolution
- 12 MP
- Shutter
- Rolling
A rolling shutter is fine for stop-and-go survey from a stationary vehicle; a moving vehicle changes the camera choice, below. Run your own lane width and crack width through the calculator:
Dark cracks on dark asphalt: threshold the top-hat, not the gray frame
The mask removes the border; it does nothing for contrast. Asphalt brightness drifts across a frame by more than the crack-to-asphalt difference, so a single global threshold on the gray frame fails everywhere, not only at the edges. Make the contrast local:
Closing bridges a dark feature narrower than its structuring element, then subtracting the original frame cancels the asphalt and leaves the crack bright on a near-zero background. The scikit-image morphology guide describes closing as the operation that removes small dark specks and connects thin bright structures — here you keep what it removes. One fixed threshold now works on the top-hat image; multiply by the mask and only pavement cracks survive.
Size the disk from the pixel scale. A 3 mm crack at 0.90 mm per px is 3.3 px wide, and the element needs about three times that in diameter: 10 px, a disk of radius 5 px. In road terms the element is 9 mm across, wide enough to bridge every crack you target and leave a 30 mm patch of dark aggregate alone.
Then measure what you found: skeletonize line patterns for crack centerlines — fix threshold polarity first — and measure blob area in the binary image by pixel counting. For telling crack structure from the noise that survives thresholding, the contour statistics in crack segmentation: separating cracks from noise are the next read. Where you control the light — bridges, depots, indoor slabs — dark contaminant detection on dark surfaces and scratch defect detection with lighting and dynamic thresholding cover the lighting half of the dark-on-dark problem. On a public road you rarely control light, which is why the top-hat does that work here.
Hardware that keeps the trapezoid stable
The mask assumes the road never moves in the frame. Four things keep that true:
- A rigid mount with focus and iris locked. Vibration and refocusing on a moving platform blur the frame and shift the trapezoid; the trade-offs are laid out in autofocus versus fixed focus lenses on mobile robots.
- A global shutter when the vehicle moves. A rolling shutter captured in motion bends straight cracks into curves, and bent cracks are then indistinguishable from distortion. For a moving survey, the MV-CH120-11UC is a 12 MP global shutter camera with a 1.1" sensor and a C-mount.
- Sensor format
- 1.1"
- Lens mount
- C-mount
- Interface
- USB3
- Resolution
- 12 MP
- Low distortion. Barrel distortion bows the trapezoid borders and curves cracks; keep it small, or undistort first — and if you undistort, black borders after undistortion are exactly the artifact your mask must then swallow, so mask after undistortion. The LS-FFL-0567 is a 16 mm C-mount lens rated for 20 MP on 1.1" sensors, holding distortion under 0.3 % across an iris range of F2.8-22.
- Type
- Machine vision fixed
- Sensor format
- 1.1"
- Mount
- C-mount
- Resolution
- 16-25 MP
- Short exposure when moving. At 10 km/h the road moves 10000 m / 3600 s = 2.78 m/s under the camera; 1 ms of exposure smears 2.78 mm, which is 3.1 px at 0.90 mm per px. Hold exposure at or under 1 ms at that speed — daylight supports it, tunnels and night work need added light.
If the vehicle carries no PC, smart cameras run the whole pipeline — mask, top-hat, threshold — onboard and hand up pass/fail per frame. The MV-SC5060XM-08M-WBN is a 6 MP mono smart camera with an integrated 8 mm M12 lens on GigE.
- Interface
- GigE
- Resolution
- 6-10 MP
- Sensor format
- 1/2.4"
- Shutter
- Rolling
For stop-and-go work, any area scan camera with enough pixels across the lane will do; the camera finder filters by resolution and shutter type. Match it with a low-distortion optic from the machine vision lenses category and the geometry stays honest.
Prove the border is gone
Three checks, cheapest first:
- Look. Display the edge image next to the masked edge image — in MATLAB,
imshowpair(edge(A), edge(A) .* roadMask, "montage")does it in one call. Every remaining edge must sit interior to the mask. A live binary image preview keeps the same check running while you tune. - Empty pavement. Run 100 frames of pavement you have walked and cleared. Zero detections is the pass mark; anything within 3 px of the mask boundary is a mask failure, not a crack.
- A known line. Lay a 3 mm dark line — tape or paint — at five positions, one of them parallel to and near the border. It must be detected everywhere the scale allows and nowhere beyond the far-edge row. That confirms the mask and the scale decision together.
Common mistakes
- Eroding by 1 px under a 7 px kernel. The mask must clear the detector's reach, not just the border line: radius 3 px minimum with 3×3 kernels, 5-10 px for soft or compressed borders.
- Filtering detections instead of masking the input. A distance rule deletes real cracks near the border and keeps detections that straddle it. The mask does neither.
- Masking the full rectangle because the road mostly fills it. The corners pick up shoulder, grass or guardrail, and you have manufactured new borders with the same problem.
- Thresholding the raw gray frame. The mask cannot fix contrast; that is the top-hat's job.
- Masking before undistortion. Undistortion resamples the frame and pulls the mask out of register. Undistort, then mask, then erode.
- Re-deriving the mask every frame on a moving vehicle without growing the erosion. The trapezoid jitters a few px between updates; add the jitter to the erosion radius or the border returns as a flickering line.
When a mask is not the answer
Two cases send you elsewhere. If you need crack depth, opening under load, or rut geometry — anything intensity alone cannot give you — a 3D laser line profiler measures the surface directly and has no ROI border problem, because it measures only where the line lands. And if you move to learned segmentation, published crack studies already segment cracks with instance-segmentation networks; keep the mask anyway. It crops the network's input to pavement, removes the border artifacts the network would otherwise learn, and costs one multiply.
Checklist before the first run
- Camera rigid; focus, iris, exposure and gain locked.
- Mask built from a reference frame: binarize, convex hull, erode 3 px, far edge set by pixel scale.
- Scale at the far-edge row at or under one third of the target crack width — 1.0 mm per px for a 3 mm crack.
- Empty-pavement run clean: zero detections in 100 frames.
- 3 mm test line detected at every allowed position, rejected beyond the far-edge row.
- Exposure at or under 1 ms when surveying at 10 km/h; global shutter when the vehicle moves during capture.
- Mask re-derived and erosion grown whenever the mount or the vehicle geometry changes.
More image-processing walkthroughs like this one sit under the systems topic. Next, run the system configurator from the camera step with your lane width and crack width to hand. For tunnels, night work or a moving-vehicle set-up, bring those numbers plus your survey speed to the contact page and we will size the system with you.
Questions
Why do the trapezoid borders register as cracks?
Because every linear detector keys on long, coherent gradients, and the road-to-background border is the longest, highest-contrast edge in the frame, stronger than any crack edge. Gray-level thresholding picks it up for the same reason. Pulling the mask 3 px inside the border removes that gradient from the detector's input entirely, which post-detection filtering cannot do without also deleting real cracks near the border.
How far inside the border should the mask be eroded?
At least the radius of your detector kernel: a disk of radius 3 px for a 3×3 Sobel or Canny, 5-10 px when the border is soft from focus, compression or a wide-angle lens. The cost is small. At 0.90 mm per px, 5 px of erosion gives up 4.5 mm of pavement, and border false positives cost far more survey time than that strip.
Does the mask also fix the dark-asphalt thresholding problem?
No. The mask only deletes the border; it does nothing for contrast. Cracks a few gray levels below the surrounding asphalt need a local-contrast step, a black top-hat (closing minus the original frame) with a structuring element wider than the crack, followed by one fixed threshold on that filtered image. Order matters: mask first, contrast second.
How many camera pixels do I need across a lane?
Three pixels across the narrowest crack you must report, applied over the full lane: pixels = 3 × lane width / crack width. A 3.6 m lane with a 3 mm target needs 3 × 3600 / 3 = 3600 px across the lane. Fewer pixels and you choose which half to give up: half the lane width covered, or a 6 mm crack floor instead of 3 mm. The camera resolution calculator runs the same sum.
Can cracks that touch the mask border still be measured?
Yes, up to the erosion line. A crack that runs to the boundary is truncated there, so its length is under-reported by the masked strip: 3 px, about 2.7 mm at 0.90 mm per px. Widths stay valid because the top-hat response is local to each pixel. If length at the border matters, erode less and accept a few hand-checked detections.



