defect op• Data kinds: mesh × labels → table
• Call: import fullseye as fs; fs.ledger.cad_defect_to_cad(mesh, labels, K=None, R=None, t=None, cull_backfaces=True, min_pixels=1, background=0, strict=False) (to call the implementation directly, import cadmap; cadmap.cad_defect_to_cad(mesh, labels, K=None, R=None, t=None, cull_backfaces=True, min_pixels=1, background=0, strict=False); from the registry, opscadmap.get("cad_defect_to_cad"))
2-D defect label image → a table on the CAD surface (face ID / area on the face / 3-D centroid).
labels is an (H, W) integer label image (background is ignored; a bool mask is also allowed). For each label it casts rays for all pixels and accumulates the hit faces and the real area the pixels occupy on the face. The area is not the pixel count but
dA = Z^2 * cosα / (fx * fy * |cosθ|)
where cosα is the tilt from the optical axis and cosθ the angle between the ray and the face normal. The more obliquely a face is seen, the larger the area 1 pixel covers -- this is exactly the Jacobian of perspective projection, and leaving it as Z^2/(fx*fy) makes defects on tilted faces come out small (at 60 degrees exactly half).
The return is a list of dicts, one per label (table sort):
• label label value.
• n_pixels number of pixels of that label.
• n_hit number of pixels that hit the CAD. hit_fraction = their ratio.
• area real area on the surface (mesh length unit to the power 2). Sum over the hit pixels only; pixels that did not hit are not added.
• area_naive sum of Z^2/(fx*fy) alone (= value ignoring the tilt). Both are returned so that users can check for themselves whether the tilt correction is working.
• face_ids ascending unique list of hit faces (int64 array).
• face_areas per-face area in the same order as face_ids.
• centroid area-weighted 3-D centroid (world coordinates). NaN if 0 hits.
• depth_mean mean Z of the hit pixels. NaN if 0 hits.
• winding_fixed bool -- whether an inward-wound closed mesh was detected and fixed. Every record carries the same value (because it is a per-mesh property).
Regions smaller than min_pixels are dropped. Regions with 0 hits are not deleted but kept with area = 0.0, hit_fraction = 0.0 -- deleting them would let "defects that were outside the CAD" silently vanish from the table.
Winding is handled as in the other ops (cull_backfaces=True detects a closed inward-wound mesh → by default auto-fix + winding_fixed; with strict=True ValueError). Honest limit: since a list of records is returned, if labels is all background or every region is below min_pixels so that the list is empty, there is nowhere to record the fact of the fix. In that case not even 1 defect was imaged in the first place (there is no wrong number it could return). If you need a place to record it, use strict=True or query just 1 pixel with cad_pixel_to_surface on the same mesh.
• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).
• Operator provenance and references — the sources of the research/methods this op family came from.
• The canonical algorithm (author, year) and its uses are named in the family usage guide above.
• defect_to_cad — py -3.11 examples/defect_to_cad.py
table as input)—
defect)—
*Provenance: cadmap.py — CADMAP operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.