Low res stream during scanning for instant high res captures

This commit is contained in:
jaknapper 2025-05-07 10:39:05 +01:00 committed by Julian Stirling
parent a9fdd0ea3e
commit 17f3bbe646
3 changed files with 39 additions and 9 deletions

View file

@ -79,6 +79,16 @@ class CameraProtocol(Protocol):
"""Acquire one image from the preview stream and return its size"""
...
def start_highres_streaming(self) -> None:
"""Start (or stop and restart) the camera in a configuration for low
res streaming and instant high res captures"""
...
def start_streaming(self) -> None:
"""Start (or stop and restart) the camera in the default streaming
configuration which balances stream and capture quality"""
...
class BaseCamera(Thing):
"""A Thing representing a camera
@ -182,6 +192,17 @@ class CameraStub(BaseCamera):
"""Acquire one image from the camera and return as a JPEG blob"""
raise NotImplementedError("Cameras must not inherit from CameraStub")
@thing_action
def start_highres_streaming(self):
"""Start (or stop and restart) the camera in a configuration for low
res streaming and instant high res captures"""
raise NotImplementedError("Cameras must not inherit from CameraStub")
@thing_action
def start_streaming(self) -> None:
"""Start (or stop and restart) the camera in the default streaming
configuration which balances stream and capture quality"""
raise NotImplementedError("Cameras must not inherit from CameraStub")
CameraDependency = direct_thing_client_dependency(CameraStub, "/camera/")
RawCameraDependency = raw_thing_dependency(CameraProtocol)

View file

@ -65,6 +65,14 @@ class CaptureThing(Thing):
logger.warning(e)
raise CaptureError("An error occurred while capturing after 5 attempts")
@thing_action
def stop_streaming(self, cam: CamDep):
cam.stop_streaming()
@thing_action
def restart_stream(self, cam:CamDep):
cam.restart_stream()
@thing_action
def _capture_array(self, cam: CamDep, metadata_getter: GetThingStates, logger: InvocationLogger, stream: str = 'main'):
"""Capture an image in memory and return it with metadata

View file

@ -182,6 +182,8 @@ class SmartScanThing(Thing):
self._scan_images_taken = 0
self._stitch_resize = 1
self._cam.start_highres_streaming()
# Don't set self._scan_data dictionary. This is done at the start of _run_scan
try:
@ -202,6 +204,7 @@ class SmartScanThing(Thing):
# Error must be raised so UI gives correct output
raise e
finally:
self._cam.start_streaming()
# However the scan finishes, unset all variables and release lock
self._cancel = None
self._scan_logger = None
@ -404,19 +407,17 @@ class SmartScanThing(Thing):
test_jpg = self._cam.grab_jpeg()
test_image = np.array(Image.open(test_jpg.open()))
test_image_res = list(test_image.shape[:2])
test_image_res = list(test_image.shape)
csm_image_res = [int(i) for i in self._csm.image_resolution]
if test_image_res != csm_image_res:
raise RuntimeError(
"Cannot start scan as it is set up to capture with a resolution that "
"has not been mapped.\n"
f"Scan resolution: {test_image_res}\n"
f"camera-stage-mapping resolution {csm_image_res}."
)
# If current stream width is different to csm calibration width,
# perform the conversion here
res_ratio = csm_image_res[0] / test_image_res[0]
# get displacement matrix. note it is for (y, x) not (x, y) coordinates
csm_disp_matrix = self._csm.image_to_stage_displacement_matrix
csm_disp_matrix = np.array(self._csm.image_to_stage_displacement_matrix)
csm_disp_matrix *= res_ratio
# Calculate displacements in image coordinates
dx_img = test_image.shape[1] * (1 - overlap)