Skip to content

Coordinate frame: exported plane, selection planes, file frame, size mismatch (QuPath #21) - #27

Merged
guijacquemet merged 3 commits into
mainfrom
claude/phase2-qupath-coordinate-frame
Oct 13, 2026
Merged

guijacquemet merged 3 commits into
mainfrom
claude/phase2-qupath-coordinate-frame

Conversation

@guijacquemet

@guijacquemet guijacquemet commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Phase 2, theme 2 (coordinate frame) for the QuPath host: docs/SPEC_WRONG_SCIENCE.md section 1 of LabConstrictor-Tools and wrong_science.coordinate of conformance.json (CF-01..CF-14; CF-09 and CF-10 are the QuPath-specific cases). Fixes #21. The Napari reference is LabConstrictor-napari #52.

What changes

  • One exported plane (1.2.7, 1.1.9, CF-10). The plane the viewer shows when Run is pressed is read once and is the plane that is exported for the image open in QuPath: a selection area, the viewport and the whole image (the whole image used to be exported from z=0, t=0 while the viewport used the viewer plane). Points and outlines are drawn on that plane, so a result with no t/z lands on the exported plane, not on plane 0. A project image or a file has no viewer plane and is exported from z=0, t=0 (as before).
  • Selections cannot silently mix planes (Respect QuPath ROI Z/T planes when exporting selected areas and RegionOf masks #21). All selected annotations that define a crop (Image area: Selected annotation(s)) or a RegionOf mask must lie on one plane and on the exported one. Annotations on different planes are refused with selection_mixed_planes, annotations on one other plane with selection_plane_mismatch; the host never switches the plane. The refusal is one sentence (z/t named), logged with its code and carried in the outcome as reason; nothing is exported or drawn, no results folder is made.
  • File input is its own frame (1.3, CF-07/08). A result whose source is a file is never drawn on the open image: points are a table, outlines a labelled file (path in the sentence), and the status says file input: results are in the file's pixel frame (conformance file_input_note). An output's source is now the input its ApplyTo names (also when the result message does not repeat it), else the first image input.
  • Size mismatch is stated (1.1.7, CF-11). An image or labels result that declares ApplyTo and has another size than what the tool received (the crop, if a crop was exported) is said once in the status line with the conformance sentence 'labels' is 6 x 4 but 'Image' was exported as 12 x 8; shown at the pixel origin, not aligned.
  • Placement c = x0 + (x + 0.5) * downsample and [x, y]/(y, x) were already right; they are now pinned by the tests below (CF-01, CF-09, CF-12, CF-14).

Issues

Tests

tests/gui_test_frame_body.groovy (53 checks, picked up by tests/run_gui_ci.sh, README updated). It reads CF-01..14 from the conformance file of labconstrictor-tools (LC_CONFORMANCE, else python -m labconstrictor_tools.conformance --path of the registered app), builds ASYM (tests/fixtures/asym.tif, 8 x 12, 100*y + x) and the same image as 2 time points x 2 z-planes (asym_zt.tif), and drives the real dialog and a real worker (tests/frame_app, new test app frame, registered by tests/ci_setup_apps.sh; its tool reports what it received: image shape and pixels, mask shape and pixels). Checked: the worker's input (exported crop values 204 / 509, mask pixels equal rect_mask_pixels and values 203..305, mask all ones in the crop shape), the exported files, the drawn coordinates read back from the annotations (point at c, outline box), the planes (z/t) of every annotation, nothing else drawn, results folder count unchanged on a refusal, the refusal sentences and codes (codes compared with host_internal_codes), CF-12 (Replace with another frame), CF-14 placement arithmetic at downsample 2 and 4 with offsets.

  • QuPath fixtures: the fixture rectangle is given with centres at integers, QuPath pixel i spans [i, i+1), so it is drawn at vertex + 0.5 (spec 1.1.3: target_px + 0.5).
  • Not applicable to QuPath (printed as NOT_APPLICABLE, never as passed): CF-02..06 and CF-13 (a QuPath image has no transform, identity by construction, spec 1.3). Unsupported (printed as UNSUPPORTED): CF-14 export at downsample 2 and 4 (the host exports at 1.0 only); only the placement arithmetic of those variants is checked.
  • Sabotage checks (production code broken in a copy, the tests must fail): 19 mutants: whole image exported on plane 0 again; results drawn on the default plane; mismatch check removed; mixed check removed; mask without a plane check; area without a plane check; x0/y0 ignored; downsample ignored; +0.5 removed for points; +0.5 removed for outlines; x and y swapped for points; mask not shifted by the crop offset; file note removed; size-mismatch sentence removed; frame = whole image instead of the crop; file results drawn on the open image; mixed-planes code missing; the area's plane read as 0/0; the mask area's plane. 17 caught at first. One mutant (the plane field of the whole-image area inside selectionMask) is equivalent (the mask code reads only that area's size and offset). One was missed (the area resolution reading the plane as 0/0: no test had the viewer off plane 0 with an Image area), so I added CF-10h (selection area, viewport and a (0,0) selection while the viewer shows (1,1)); it is now caught. The first fixture also showed that labels_to_shapes simplifies outlines, so the test tool writes the exact box instead.
  • A first CI-style local run hung on QuPath's "save changes?" dialog when the test opened another image with annotations; the body now marks the image unchanged first.

Existing tests changed

None. (No existing test pinned the old whole-image plane; the full qupath-gui suite is green with the new body.)

Spec gaps and conservative choices

  1. Project image or file, no viewer plane: the spec names only the viewer's plane; I export those from z=0, t=0 (their results are not drawn on an image anyway).
  2. Point annotations in a selection are ignored for the plane check (they define neither crop nor mask).
  3. Refusal sentences are mine (the spec fixes the codes and the suffix (nothing was changed; files are in <path>)); the suffix is not added because a plane refusal happens before any file is written.
  4. 1.1.5 vs 1.3 for a file source: I followed 1.3/CF-07 (qupath: table_and_file); outlines are "listed as a file" in the results window and the status carries the conformance note.
  5. CF-11 in QuPath: a result image is always opened as an image of its own and never aligned, so the sentence is said whenever an ApplyTo result has another size, and nothing is said when the sizes agree. source in the sentence is the label of the input parameter.
  6. Axes("YX") guard kept: a tool that declares axes still refuses a whole-image export of a stack, with the Tools sentence (existing behaviour, wrong_dimensions); the spec is silent. The exported plane for a tool without declared axes is the viewer plane.
  7. The plane is read before export, once per run. Run identity (RUN-01..07: the image or its size changing during the run, target_unavailable) is theme 4 and is not done; hence Keep QuPath image identity and result coordinates tied to the image used at run start #16 stays open.
  8. Not changed: hs_err_pid*.log files committed at the repo root (not mine).

Not verified

  • CI is Linux only (qupath-gui on Ubuntu, QuPath 0.7.0, Xvfb); Windows and macOS were not run by anything, here or in CI. Other QuPath versions not tried.
  • No human at a real display; everything went through the dialog object and a real worker on Xvfb.
  • Not tried: a real multi-gigapixel pyramid, a rotated viewer, downsample other than 1 (unsupported by the host), channel/z combined with PickChannel, a project image that is also the open image.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Y2SN8SuEakTdiWy3F2WUqN

guijacquemet and others added 2 commits October 13, 2026 14:34
…ze mismatch (SPEC_WRONG_SCIENCE section 1)

- the image open in QuPath is exported on the plane the viewer shows at run start, whole image included; points and outlines are drawn on it (1.1.9, 1.2.7, CF-10)
- selected annotations must lie on one plane and on the exported one: selection_mixed_planes / selection_plane_mismatch, for the Image area and the RegionOf mask (QuPath #21)
- a file input is its own pixel frame: results are a table and a file, the status says so (1.3, CF-07)
- an ApplyTo image or labels result of another size than what the tool received is said once (1.1.7, CF-11)
- tests/gui_test_frame_body.groovy runs CF-01, 07..12, 14 from conformance.json against a real worker (tests/frame_app)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2SN8SuEakTdiWy3F2WUqN
… viewport, mismatch while the viewer is off plane 0)

Found by a sabotage check: reading the plane as 0/0 in the area resolution was not caught.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2SN8SuEakTdiWy3F2WUqN
@guijacquemet
guijacquemet marked this pull request as ready for review October 13, 2026 15:21
@guijacquemet
guijacquemet merged commit 5092a0c into main Oct 13, 2026
2 checks passed
@guijacquemet
guijacquemet deleted the claude/phase2-qupath-coordinate-frame branch October 14, 2026 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant