[testable] Full-sensor plate solving + cached optical calibration - #33
Closed
mrosseel wants to merge 2 commits into
Closed
[testable] Full-sensor plate solving + cached optical calibration#33mrosseel wants to merge 2 commits into
mrosseel wants to merge 2 commits into
Conversation
…tion The camera cropped every exposure to a centred square before solving, throwing away roughly half the sensor area (imx462: 1920x1080 down to 980x980). Cedar Solve has no trouble with the whole frame, so that discarded area is free plate-solving sensitivity. The camera now publishes two frames per exposure: the 512x512 display frame, unchanged, and a solve frame covering the whole sensor at native scale. Bayer sensors are binned 2x2 for the solve frame, which removes the RGGB modulation the old downscale to 512x512 used to smooth away. Everything downstream of the solver -- SQM photometry, the preview overlay, the alignment marker -- is written against the display frame, and SQM in particular is calibrated to its plate scale. So solves are projected back onto the display frame in one place (project_solution_to_display), keeping those consumers unchanged. SolveGeometry owns the mapping, composed from the affine transform of each pipeline stage. The solver also stopped rediscovering the optics on every frame. It passed a fixed 12 +/- 4 degree window and never passed a distortion estimate at all. The first successful solve of a run now captures the measured FOV and lens distortion; later solves get a +/-0.5 degree window and the measured distortion as a starting point, which speeds up pattern matching and improves centroid matching towards the frame corners -- the part of the image the crop used to discard. A run of failures discards the calibration and reopens the window. Full frame is on by default and can be turned off with solver_full_frame. It is disabled automatically when the camera has no sensor profile, or when camera_rotation is set to something other than a quarter turn, since rotating a non-square frame by an arbitrary angle would clip the corners.
Owner
Author
|
Wrong repo — the device reads brickbots/PiFinder@nixos-manifest, so a build published to mrosseel's manifest is never visible to it. Reopening against brickbots/main with the same head. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Device-testable build of the full-frame solver work (upstream PR brickbots#554), merged onto
nixosso it can actually be built and installed. Not for merge — this exists to produce an installable image.What to expect on the device
Two changes, both in the solver:
Full-sensor solving. The camera cropped every exposure to a centred square before solving — on the imx462, 1920×1080 down to 980×980, discarding roughly half the sensor. The camera now publishes two frames per exposure: the 512×512 display frame (unchanged — UI, focus, preview, align, SQM) and a full-sensor solve frame at native scale, used only by the plate solver. Bayer sensors bin 2×2 for it.
Cached optical calibration. The solver passed a fixed
fov_estimate=12.0, fov_max_error=4.0and never passed a distortion estimate at all. The first successful solve of a run now captures the measured FOV and lens distortion; later solves get a ±0.5° window and that distortion as a starting point.What to check
Matchesat the same exposureFull-frame solving enabled: solve frame 540x960, thenOptical calibration: FOV … distortion …Escape hatch:
solver_full_frame: falsein config reverts to the old crop path without reflashing, so you can A/B on the device.Note the horizontal FOV grows only modestly — after the camera's quarter turn the solve frame's horizontal axis is the sensor's short side, which the square crop already spanned. Total area still roughly doubles; the extra sky arrives vertically.
Status
Never run on real camera hardware.
capture_pair, the 2×2 Bayer bin, and the geometry mapping all get their first real exercise here — that is the point of this build.Verified in CI terms: ruff, mypy and 1202 unit+smoke tests pass. Benchmarked over 220 archived sweep frames (imx462 + HQ): doubling the solve frame's pixel count costs −0.02 ms in cedar-detect, i.e. nothing measurable; total extract+solve stays 0.6–8% of one exposure cycle.
Best target is pifinder-mr2 (imx462): biggest area gain, and it exercises the new Bayer bin path.
Merge conflicts resolved here, worth a glance
camera_pi.py— the full-frame refactor splitscapture()into_read_raw/_display_frame, which separated the per-frame optical-black measurement from the radiometer sample that consumes it. Threaded viaself.last_optical_black; ruff caught the break.camera_interface.py— kept bothtest_mode_onandsolve_frameinitialisation.test_full_frame_solve.py— tetra3 is a submodule on some branches and a uv dependency here; the path entry is now conditional.