Live button-driven scanning with EEPROM calibration
- ScanSession: scan-mode context manager with bright-pixel auto-exposure and sensor colour gains; tools/scan.py scans on the scan button with live stitching - Read-only EEPROM access and calib.py parser (laser geometry, intrinsics, colour gains, black/white flat-field samples); flat-field correction in Stitcher - OV7740 sensor access via the MCU proxy; colour gains from EEPROM fix green cast - Stitcher: colour support, high-passed registration (robust on blank paper) - RE notes on the Mac app's colour, exposure, stitching and button handling Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+9
-6
@@ -10,7 +10,8 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
import cv2 # noqa: E402
|
||||
import numpy as np # noqa: E402
|
||||
|
||||
from myscan.stitch import ROT_GAIN, Stitcher, laser_deltas # noqa: E402
|
||||
from myscan import calib # noqa: E402
|
||||
from myscan.stitch import ROT_GAIN, Stitcher # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
@@ -19,24 +20,26 @@ def main():
|
||||
ap.add_argument("-o", "--out", help="output image (default <dir>/page.png)")
|
||||
ap.add_argument("--no-refine", action="store_true", help="lasers only, no image registration")
|
||||
ap.add_argument("--rot-gain", type=float, default=ROT_GAIN)
|
||||
ap.add_argument("--no-flat", action="store_true", help="skip the EEPROM flat-field correction")
|
||||
ap.add_argument("--no-wb", action="store_true", help="skip white-patch balancing")
|
||||
ap.add_argument("--start", type=int, default=0)
|
||||
ap.add_argument("--end", type=int)
|
||||
a = ap.parse_args()
|
||||
|
||||
rows = list(csv.DictReader(open(os.path.join(a.dir, "records.csv"))))
|
||||
v = np.array([[int(r[f"v{k}"]) for k in range(6)] for r in rows])
|
||||
deltas = laser_deltas(v)
|
||||
frames = [int(r["frame"]) for r in rows]
|
||||
rng = range(a.start, a.end if a.end is not None else len(rows))
|
||||
|
||||
flat = None if a.no_flat else calib.FlatField(calib.load())
|
||||
st = None
|
||||
for i in rng:
|
||||
im = cv2.imread(os.path.join(a.dir, f"f{frames[i]:05d}.png"), cv2.IMREAD_GRAYSCALE)
|
||||
im = cv2.imread(os.path.join(a.dir, f"f{frames[i]:05d}.png"), cv2.IMREAD_UNCHANGED)
|
||||
if st is None:
|
||||
st = Stitcher(im.shape, refine=not a.no_refine, rot_gain=a.rot_gain)
|
||||
st.add(im, deltas[i])
|
||||
st = Stitcher(im.shape, refine=not a.no_refine, rot_gain=a.rot_gain, flat=flat)
|
||||
st.add(im, v[i])
|
||||
out = a.out or os.path.join(a.dir, "page.png")
|
||||
cv2.imwrite(out, st.image())
|
||||
cv2.imwrite(out, st.image(white_balance=not a.no_wb))
|
||||
print(f"{st.n} frames -> {out} {st.stats}")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user