Goal (user, 2026-08-14): grow Fullseye toward an HDevelop/HALCON-class practical environment — concretely (1) handle more data formats, especially 3-D objects a robot (evis/onocollo/hillco) can import and grasp; (2) add more operators that differentiate from HALCON, leaning on Python’s affinity with CNN/RL/ML; (3) review the Studio UI with external AI. Worked autonomously (user at work). All changes local; not pushed (human gate).
Starting point (audited): Fullseye could import zero object formats; only float64
[0,1] grayscale/RGB survived end-to-end; 16-bit/float/complex/>3-channel were lost;
save_ply was write-only; the volume sort had no loader. Four new numpy-native
modules close most of that gap, each wired into the api facade + fullseye package.
mesh.py — 3-D object import, zero dependencies (in-house parsers from the
public specs, avoiding GPL plyfile): read_mesh (OBJ / STL bin+ascii / PLY
ascii+bin LE&BE / OFF → (V,F)), read_points (PLY/XYZ/OBJ/PCD-ascii → cloud),
write_mesh (OBJ, PLY-ascii), sample_surface, mesh_to_points, voxelize
(surface), bounds/recenter/normalize_scale. 50 tests. This is the evis
answer: fullseye.read_mesh("part.stl") → sample_surface → feeds the existing
estimate_normals/registration/icp grasp stack (verified e2e).volio.py — volumetric/medical import via SimpleITK (already an extra) +
tifffile: read_volume (DICOM series/dir, NIfTI, NRRD, MetaImage, Analyze, multipage
TIFF, raw, NPY/NPZ) → (vol (D,H,W) float64, VolumeMeta{spacing,origin,direction}),
write_volume, list_dicom_series. Feeds the existing volume op sort. Raw HU kept
(not crushed to [0,1]). 26 tests. Extra: volume = [SimpleITK, tifffile].raster.py — bit-depth-preserving raster + metric depth: read_raster
(16-bit PNG → uint16, float/16-bit/tiled TIFF, PFM), to01, read_depth (16-bit-mm
PNG / float TIFF / PFM → metres + invalid mask), read_pfm/write_pfm, save16.
21 tests. Extra: raster = [imageio, tifffile]. Bug fixed in imgio.load(): an
existing but cv2-undecodable file (e.g. float32 TIFF) used to raise a misleading
FileNotFoundError; it now falls back to raster/PIL or raises a clear “cannot decode”.render3d.py — makes an imported object “pay rent”: render_mesh (numpy
barycentric z-buffer → depth / silhouette-region / normal map), look_at /
intrinsics_from_fov / auto_view, mesh_to_sdf (signed-distance volume, ray-parity
sign, watertight), voxelize_solid (interior fill), marching_cubes (optional
scikit-image). 18 tests. Zero core deps.Honest notes: mesh.voxelize is surface (cells a triangle crosses) and
render3d.voxelize_solid is centre-inside on the same grid — different, both-correct
criteria, so solid is not a superset of surface (a naive solid ⊇ surface check is wrong).
render’s default view is head-on (flat depth); SDF sign needs a watertight mesh; PLY/OBJ
custom attributes beyond position/rgb are dropped; 16-bit PNG through imgio.load is still
demoted (use raster.read_raster for bit-depth-sensitive reads).
Three more zero-dependency numpy modules turn imported geometry/volumes into robot-usable results — all wired into the facade, each independently smoke-verified:
grasp.py — antipodal parallel-jaw grasp synthesis: grasps_from_mesh /
sample_antipodal_grasps, force_closure (Nguyen 1988), ferrari_canny_quality
(approximate epsilon), rank_grasps, grasp_pose, collision_free. The “evis
grasps objects” payoff — V14 only claimed this in a docstring; it was never
implemented (verified). Smoke: a thin box yields 1412 grasps, best width = the box’s
thin dimension, 98 % gripping across the narrow face; same-side pairs correctly rejected.meshrepair.py — sim-ready bodies: is_watertight/boundary_edges, weld_vertices,
orient_consistent, fill_holes, smooth_taubin (shrink-free), decimate_qem
(Garland-Heckbert 1997), convex_hull, inertia_tensor (Mirtich 1996, exact),
components. Smoke: unit-cube inertia = diag(1/6) to 1e-16; open cube → fill_holes →
watertight. Feeds MuJoCo collision/inertial bodies for evis.volops.py — makes volio’s CT/medical volumes analyzable (the volume sort had only
threshold): vol_frangi/vol_sato (vessel/tube enhancement), vol_label
(6/18/26-connectivity 3-D CC), vol_distance_transform, vol_region_props
(volume/centroid/sphericity), vol_gradient_magnitude, vol_local_maxima,
vol_watershed (optional skimage). Differentiates: HALCON has no voxel image type. Its
agent found + fixed 2 real bugs (constant-volume amplification; cap message).Session total: 7 new numpy-native modules (mesh, volio, raster, render3d, grasp, meshrepair, volops) + the imgio fix + the Studio UI fixes. Full suite 2834 passed / 0 failed, all local, not pushed.
Two more data modalities, both HALCON differentiators (verified against the corpus), zero-dep plain modules wired into the facade:
complexops.py — first-class complex128 images: cx_fft/cx_ifft (retain the
complex field, unlike the existing real-only FFT ops), magnitude/phase/real/imag
bridges, phase_unwrap (Herraez 2002 quality-guided) — HALCON ships fft/complex
ops but zero phase-unwrap operators; smoke recovers a wrapped multi-2π ramp to
1.4e-14. Plus cx_wiener_deconvolve, cx_apply_transfer_function, cx_bandpass.
21 tests.specops.py — multispectral / hyperspectral cubes (H,W,B>3): a numpy-native
ENVI reader/writer (BSQ/BIL/BIP, no spectral/rasterio dep), spec_angle_mapper
(Kruse 1993), spec_index (generic NDVI-style normalized difference), spec_pca /
spec_mnf, spec_unmix (fully-constrained least squares — recovers known abundances
exactly), spec_endmembers_ppi, spec_continuum_removal. A corpus scan returns 0
HALCON spectral operators. 26 tests. Named specops (not spectral) so a
pip install -e does not shadow the Spectral-Python (SPy) package.Plus examples/import_and_grasp.py — the evis story end to end (import → sim-ready with
exact inertia → grasp → render; verified: box mass 0.28 kg, grasp width = the box’s thin
dimension). Session total: 9 new numpy-native modules + the imgio fix + the Studio UI
fixes + the capstone example. Full suite 2881 passed / 0 failed, all local, not pushed.
Reviewed studio.py with Codex + Copilot (read-only) plus a visual (offscreen)
pass. Verdict after verifying each finding against real code: 13 confirmed, 2 partial,
1 false-positive (the “drag-reorder is race-prone” claim — exercised all 30 single-row
moves, 0 mismatches; multi-select is impossible, so not a bug). Fixed the confirmed,
non-architectural ones (focus rings, disabled-slider styling, file-I/O error handling,
dirty-state + confirm, enabled-state sync, command-palette single-run, shortcut scoping,
malformed-pipeline validation, accessibility, knob debounce 8→1 eval, render dedup 2→1),
each with a regression test (test_studio.py 30→50). Full report:
docs/STUDIO_REVIEW_2026_08_14.md. Deferred (needs user sign-off, architectural):
async execution on a QThreadPool (heavy op still freezes the UI), a QAbstractListModel
rewrite. Bonus bug filed: imgio.save ignores cv2.imwrite’s False return (a failed
save can still flash “saved”).
Two design workflows (a 12-phase format roadmap + a 26-item TRIZ CNN/RL/ML differentiation track, both paper-grounded and honesty-filtered) produced a clear identity: Fullseye is a numpy-native perception library that designs its own pipelines, with classical and learned ops interchangeable behind one op interface, one algebra across 2D/3D/hyperspectral/point-cloud/time. The highest-leverage differentiators require Wave-0 changes to the evolution engine, which I did not make autonomously because they alter the north-star (evolution + honest holdout). Verified against real code, for the user to decide:
ops.py:652: cands[int(t*len(cands))]).
Registering optional/learned ops changes len(cands) and remaps every genome for
that sort — a champion is only reproducible under the same installed backends. Fix =
stable op slots + champions pinned by name (pipeline_str already emits names).evolve.py: n_train=14, n_holdout=8, holdout =
same synthetic generator at seed+10000, read every generation but never selected on).
Structurally thin: no calibration split, no locked-once holdout. Fix = 3-way split.Problem.from_pairs + real-frame problem sets
before any learned/ML claim is meaningful.Only after Wave-0 do the learned-op layer (host + descriptor/vector sorts +
classify_head closing the documented classification gap + anomaly inspector) and the
optional learned perception ops (SAM/RAFT/MiDaS/RTMPose — all permissive; never
SuperPoint/SuperGlue = non-commercial) become honest. These are the user’s call.
pip install), 3-D volume ops
(Frangi/Sato vesselness — volume sort has only threshold today), spectral/HDR/complex.dispositions.py honest-coverage fix: its stale MODEL_KW heuristic
(stereo/pose/disparity/calibrat) mis-files ~250 3-D ops as out_of_scope_model
though stereo/registration/pointcloud already implement them → coverage under-reported.Source of truth: memory project_imgevolve / reference_imgevolve_usage /
project_imgevolve_goal_knowledge_layer_2026_08_13.