Repository navigation
Upgrade to pyopticfilm 1.3.8 - #1519
Merged
marcinz606 merged 1 commit intoOct 26, 2026
Merged
Conversation
jboneng
marked this pull request as ready for review
October 26, 2026 18:11
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.
This PR upgrades the pyopticfilm backend to use pyopticfilm version 1.3.8, changes in v1.3.8 are:
[1.3.8] - 2026-10-26
Added
pyopticfilm.registration): hierarchical windowed phase correlation with Guizar-Sicairos subpixel refinement on the refine ROI, mode-specific planes (Multi-Pass luminance, Multi-Exposure clip-aware, RGB↔IR gradient maps), integer-exact and separable bilinear/Keys-cubic resampling, and Multi-Pass row-banded Y profiles. ME short/long, Multi-Pass stacking, and IR→RGB alignment use this engine only.tools/audit_me_bracket --alignandtools/bench_registrationreport accuracy, apply MP/s, and staged timings.Scanner.button_state(timeout_ms=...)reads the USB interrupt endpoint (0x83) once and returns thepyopticfilm.asic.buttons.Buttonvalues pressed since the last read:QUICK_SCAN(0x08) andINTELLI_SCAN(0x40). With no press it returns an empty set, whether the read times out or the scanner answers with an empty packet. The scanner holds a press until it is read, so polling every few hundred milliseconds catches every press, one per poll. Tested on the 8300i SE and 8200i SE; the 8100 V2 is untested. Other ASICs don't have the method yet (see Notes for integrators).Gl128Common, every registration point, the tests and goldens to add, thescan_readysign-off steps, and pitfalls from adding the 8100 V2 and 8300i SE. Linked fromCONTRIBUTING.md.examples/buttons.py: polls the buttons and prints each press with the action a host would map it to (preview or full scan). The README lists both examples and has a short buttons section.Fixed
warp_shift/ linear / cubic / integer match bandedwarp_row_shifts(dst = src(x - dx, y - dy)), so Translationapply_transformactually aligns. ROI integer pre-shift uses the same convention. Guizar subpixel refine matches 5×5 centroid sign (ME/MP); RGB↔IR refine stays phase-only centroid.0xAF = 0x7F. Every SilverFast capture, on all three models and at every PPI from 150 to 7200, writes0xFFbefore that feed. With0x7Fthe feed ran slower and stopped about 270 steps short, so at 1800 ppi on the 8200i SE the frame began 34 rows higher than SilverFast's. pyopticfilm also checked for the end of the first feed only every 55 ms while the carriage kept moving, so the frame moved by up to 15 rows from scan to scan. It now checks every 2 ms. On the 8200i SE the frame now lands within 1 to 2 rows of SilverFast's in every scan.docs/register-reference.mdnow lists0xAF's feed values.0x21 = 0x04), about 0.9 s after it starts on every model and PPI. If the carriage started off home and missed that signal, pyopticfilm waited up to 30 s while the feed ran its full step count, driving the carriage into the end of its travel and dropping the scanner off USB. That feed now gives up after 2.5 s, cuts motor power and raisesMotorTimeoutError.0x21read0x04. On the 8100 V2 that probe could read0x04about 50 ms into the second (scan-start) feed while the carriage was still moving, so pyopticfilm cut motor power mid-ramp: the feed stalled with a whine and the next park took 2 to 2.5 s. SilverFast never reads0x21on that feed, on any of the three models. It waits on status0x101untilFEEDFSHis set and the motor has stopped, about 1.2 s after START. pyopticfilm now does the same on the second feed. The first (reference) feed still stops on the probe, as SilverFast's does.docs/register-reference.mdnow describes0x21per feed and per model, correcting its earlier claim that the V2 vendor driver never reads it.Changed
areais now cut to the inch after line shift and unstagger. Scanner registers and travel are unchanged. Crops and Scan Lab's Full window keep their current height.mgrid). Typical estimate on 1800/3600 dpi RGB↔IR drops from multi-second to a few hundred milliseconds.uv.lockis committed, souv syncinstalls the same dependency versions on every checkout.Removed
opencv-python-headlessis gone from dependency groups;tools/audit_me_bracket --engine={opencv,both}andpass_align.opencv_align_availableare removed. Pass registration and audit tools are NumPy-only.Notes for integrators
96 × dpi / 7200px (16 / 24 / 48 at 1200 / 1800 / 3600 dpi) and show slightly more of the frame on the left. Colour shading cached for the old window is re-measured automatically on the first scan, because the cache is keyed by window start and width.areacrops move with the frame.FEEDFSHinstead of stopping on the vendor probe (#111), on every GL128 model. It was tested on one 8100 V2 (36 full-length feeds). The frame position on the 8200i SE and 8300i SE has not been re-measured against SilverFast since this change.Scanner.button_state()returns an empty set when no button was pressed; aUsbErrorfrom it is a real USB failure, not an idle poll. On GL845, GL843 and GL842 scanners the method raisesAttributeError, so checkhasattr(scanner.asic, "button_state")first. Always passtimeout_ms:Nonefalls back to the device's general USB timeout. Pause polling while a scan runs, and start scans from the host's normal scan path rather than the polling thread.Contributors
@theaino
@TobbyTravel
@krixkrax615