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
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 detection → Hough Line Transform finds thin, non-horizontal line segments (stringing is rarely horizontal)
- Adaptive threshold → morphological 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
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
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]
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)
| 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:
- SupportSage — AI support optimization
- FilamentDB — Filament parameter database
Top comments (4)
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?
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:
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.
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!
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.