Hama myScan Linux driver tools: scan mode, frame decoding, stitching
UVC extension-unit control (mouse/scan mode, LEDs, exposure), JPEG header fix and embedded laser record decoding, session recorder, and a stitcher that combines laser dead reckoning with phase correlation and ECC refinement. FINDINGS.md holds the reverse-engineered protocol and laser calibration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Put the myScan into scan mode the way Hal::OVMouseManager::startVideo does,
|
||||
grab a few seconds of frames, decode the embedded sensor records, then restore
|
||||
mouse mode."""
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
sys.stderr = os.fdopen(os.dup(2), "w")
|
||||
os.dup2(os.open(os.devnull, os.O_WRONLY), 2) # silence libjpeg warnings
|
||||
|
||||
import cv2 # noqa: E402
|
||||
import numpy as np # noqa: E402
|
||||
|
||||
from myscan.frame import fix_and_extract # noqa: E402
|
||||
from myscan.xu import XU # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("-d", "--duration", type=float, default=4)
|
||||
ap.add_argument("-o", "--out", default="scantest")
|
||||
ap.add_argument("--video", default="/dev/video4")
|
||||
a = ap.parse_args()
|
||||
os.makedirs(a.out, exist_ok=True)
|
||||
|
||||
x = XU(a.video)
|
||||
print("D8 before:", hex(x.bridge_read(0xD8)))
|
||||
try:
|
||||
print("disable mouse:", x.disable_mouse())
|
||||
print("2D=60:", x.mcu_write_verified(0x2D, 0x60), " E7=28:", x.mcu_write_verified(0xE7, 0x28))
|
||||
print("start scan:", x.start_scan())
|
||||
|
||||
cap = cv2.VideoCapture(a.video, cv2.CAP_V4L2)
|
||||
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"MJPG"))
|
||||
cap.set(cv2.CAP_PROP_CONVERT_RGB, 0)
|
||||
t0, n = time.time(), 0
|
||||
while time.time() - t0 < a.duration:
|
||||
ok, f = cap.read()
|
||||
if not ok:
|
||||
continue
|
||||
raw = f.tobytes()
|
||||
clean, rec = fix_and_extract(raw)
|
||||
im = cv2.imdecode(np.frombuffer(clean, np.uint8), cv2.IMREAD_GRAYSCALE)
|
||||
cv2.imwrite(f"{a.out}/f{n:04d}.png", im)
|
||||
if n % 10 == 0:
|
||||
r = rec.raw.hex() if rec else None
|
||||
print(f"#{n:3d} {len(raw):6d}B bright={im.mean():6.1f} rec={r}", flush=True)
|
||||
n += 1
|
||||
cap.release()
|
||||
print(f"{n} frames -> {a.out}/")
|
||||
finally:
|
||||
print("enable mouse:", x.enable_mouse())
|
||||
print("D8 after:", hex(x.bridge_read(0xD8)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user