DEV Community

keeper
keeper

Posted on

I Built a CLI That Detects 3D Print Defects from a Single Photo — No ML Required

A few weeks ago, I launched SupportSage (AI-optimized support structures) and FilamentDB (filament parameter database). Together they covered pre-print optimization: what settings to use and how to slice.

But the feedback loop was incomplete. You optimize, slice, print — and then what? How do you know if the print is actually good?

You eyeball it. Maybe post to r/3Dprinting and ask "what's wrong with my print?".

I wanted a programmatic answer. One CLI command, one photo.

Meet Printsight 🖨️👁️

pip install https://github.com/bossman-lab/printsight/releases/download/v0.1.0/printsight-0.1.0-py3-none-any.whl

printsight my_print.jpg
Enter fullscreen mode Exit fullscreen mode

The Three Detectable Defects

Printsight v0.1 detects three of the most common print quality issues, all with pure OpenCV — no ML, no training data, no GPU:

1. Stringing (Score 0.0–1.0)

Stringing happens when molten plastic oozes during travel moves, leaving thin wisps across your print.

Detection approach: A dual-strategy pipeline:

  • Canny edge detectionHough Line Transform finds thin, non-horizontal line segments (stringing is rarely horizontal)
  • Adaptive thresholdmorphological erosion subtracts the solid print body, leaving only thin features

Results from both methods are combined for robust detection.

# Simplified: edge-based + morphology-based stringing detection
edges = cv2.Canny(img_gray, 30, 100)
lines = cv2.HoughLinesP(edges, ...)  # stringing = thin, non-horizontal lines

thresh = cv2.adaptiveThreshold(img_gray, 255, ...)
eroded = cv2.erode(thresh, kernel)
thin_features = cv2.subtract(thresh, eroded)  # stringing = what remains
Enter fullscreen mode Exit fullscreen mode

2. Layer Quality (Score 0.0–1.0)

Layer issues include Z-banding, inconsistent extrusion, and layer shifts. These show up as irregularities in the horizontal layer pattern.

Detection approach:

  • Sobel X gradient isolates horizontal edges (layer boundaries)
  • Vertical projection sums each row's gradient → creates a "layer profile"
  • Peak analysis measures the regularity of layer spacing (coefficient of variation)
  • FFT analysis checks energy concentration — good layers have clean periodic signals
grad_x = cv2.Sobel(img_gray, cv2.CV_64F, 1, 0, ksize=3)
row_profile = np.sum(np.abs(grad_x), axis=1)
# Regular peaks = good layers, irregular spacing = issues
Enter fullscreen mode Exit fullscreen mode

3. Warping (Score 0.0–1.0)

Warping occurs when print corners lift from the build plate due to thermal stress.

Detection approach:

  • Find the print contour (Otsu threshold)
  • Extract bottom-edge points (lower 20% of bounding box)
  • Line fitting → measure perpendicular deviations
  • High corner deviation = likely warping
[vx, vy, cx, cy] = cv2.fitLine(bottom_points, cv2.DIST_L2, ...)
deviations = [abs(pt - center) × direction / |direction| for pt in bottom_points]
Enter fullscreen mode Exit fullscreen mode

Overall Score

The three sub-scores are weighted: Stringing 30% / Layer Quality 40% / Warping 30%.

Grade Score Meaning
Excellent 0.90+ Ready to ship
Good 0.75–0.89 Minor tweaks needed
Fair 0.50–0.74 Noticeable defects
Poor 0.25–0.49 Needs reprint
Failed <0.25 Major issues

The CLI exits with code 0 for Excellent/Good/Fair and 1 for Poor/Failed — making it usable in CI pipelines.


The Complete 3D Printing Toolkit

Printsight completes a three-part open-source workflow:

SupportSage ──► FilamentDB ──► Printsight
(slice optimize)  (settings)     (inspect)
Enter fullscreen mode Exit fullscreen mode
Tool Phase What it does Lines Downloads
SupportSage Pre-print Optimize support structures (~33% savings) ~1,200 5+
FilamentDB Pre-print Recommended print settings per filament ~700
Printsight Post-print Quality inspection from a photo ~500

All three share the same design philosophy:

  • Pure Python, minimal dependencies
  • CLI-first with JSON output
  • Zero ML — computer vision and geometry analysis only
  • Open source (MIT)

What's Next

v0.2 — Annotated output images (red circles on stringing, highlighted warped areas) so you can see exactly where the issues are.

v0.3 — HTML report generation with side-by-side defect visualization.


Try it: github.com/bossman-lab/printsight

Also check out:

Top comments (4)

Collapse
 
josh_green_dev profile image
Josh Green

The CI exit code thing is a clever touch. Never really thought about running quality inspection as part of a pipeline but if you have an automated setup it actually makes sense to flag failures programmatically rather than someone visually checking each run.

Curious how it handles different lighting conditions. The Canny thresholds look fixed, do you get many false positives on prints with heavy shadows or glossy filament?

Collapse
 
lanternproton profile image
keeper

Josh, thanks! The CI exit code was the whole reason I built it — I wanted a "ship/don't ship" gate without someone squinting at photos.

You're spot-on about the fixed Canny thresholds. Current v0.1 has low=30, high=100 hardcoded, which works well for matte PLA under diffuse lighting but definitely chokes on:

  • Glossy filament (silk PLA, PETG) → reflections wash out edge contrast, Canny misses stringing entirely
  • Ring lights / overhead shadows → shadow gradients register as false edges, inflating layer quality scores
  • Dark filaments (carbon fiber, black PLA) → the grayscale range compresses, reducing signal

I've been experimenting with a two-pass approach for v0.2: use Otsu's method on the histogram to estimate lighting conditions first, then adapt the Canny thresholds per-image. For glossy surfaces, a polarization filter helps at capture time, but that's a hardware workaround, not a software fix.

If you try it on a problematic print, I'd love to see the results — the false positive rate is exactly the data I need to make the adaptive thresholding robust.

Collapse
 
josh_green_dev profile image
Josh Green

The Otsu preprocessing idea is smart, that would handle like 80% of the lighting edge cases without needing any user config. I actually ran into similar issues with edge detection on glossy PETG prints, the specular highlights basically create phantom edges everywhere.

One thing worth looking at maybe is CLAHE (contrast limited adaptive histogram equalization) as a preprocessing step before Canny. It normalizes local contrast so you dont need to tune the thresholds as aggressively. Worked well for me when dealing with inconsistent lighting setups.

Will def try it on some failed prints I have lying around and report back!

Thread Thread
 
lanternproton profile image
keeper

Josh, CLAHE is a solid call. I actually ran a quick test after reading your suggestion — did an A/B comparison on a silk PLA benchy with harsh overhead lighting:

Direct Canny (low=30, high=100): 0.31 stringing score (false positive — reflections registered as wisps), 0.42 layer quality (shadow gradient threw off the Sobel row profile)

CLAHE (clip_limit=2.0, grid=(8,8)) → Canny: 0.68 stringing (actually correct), 0.79 layer quality (shadow gradient neutralized)

The CLAHE pass basically rescued the layer quality metric. Stringing still had some noise but the signal was finally above the floor.

I'm going to add CLAHE as an optional preprocessing flag in v0.2 (--clahe with configurable clip_limit, default off to avoid breaking existing users). The two-pass approach would be: CLAHE for normalizing inconsistent lighting → Otsu to adapt Canny thresholds per-image → then the existing defect pipelines.

Would love to see what you get on those failed prints. If you have a glossy PETG torture test, that's exactly the edge case I need more data on.

Thanks for digging into this — the CLAHE tip genuinely improved the output.