Update tests for new camera streaming modes

This commit is contained in:
Julian Stirling 2026-05-26 22:28:51 +01:00
parent aff860a086
commit 7dd715da88
8 changed files with 27 additions and 35 deletions

View file

@ -107,9 +107,9 @@ def mock_picam_thing(mocker):
},
)
from openflexure_microscope_server.things.camera.picamera import StreamingPiCamera2
from openflexure_microscope_server.things.camera.picamera import PiCameraV2
return create_thing_without_server(StreamingPiCamera2)
return create_thing_without_server(PiCameraV2)
@pytest.fixture

View file

@ -5,7 +5,7 @@ from contextlib import contextmanager
from typing import Optional
from openflexure_microscope_server.things.background_detect import ChannelDeviationLUV
from openflexure_microscope_server.things.camera.picamera import StreamingPiCamera2
from openflexure_microscope_server.things.camera.picamera import PiCameraV2
from ...shared_utils.lt_test_utils import LabThingsTestEnv
@ -21,7 +21,7 @@ def camera_test_env(settings_folder: Optional[str] = None):
temporary directory will be used as the settings folder.
"""
thing_conf = {
"camera": StreamingPiCamera2,
"camera": PiCameraV2,
"bg_channel_deviations_luv": ChannelDeviationLUV,
}
app_config = {

View file

@ -9,7 +9,7 @@ from .cam_test_utils import camera_test_env
@pytest.fixture
def picamera_test_env() -> lt.ThingClient:
"""Initialise a test environment with only a StreamingPiCamera2 Thing."""
"""Initialise a test environment with only a PiCameraV2 Thing."""
with camera_test_env() as env:
yield env

View file

@ -93,13 +93,13 @@ def test_exposure_time_on_start_and_stop_stream():
print(f"Starting simulation scan {i}")
# This will need updating if we start supporting other Picamera models
# It is currently used here to mimic the behaviour in in scanning.
client.start_streaming(main_resolution=(3280, 2464))
client.change_streaming_mode(mode="full_resolution")
time.sleep(0.5)
for _j in range(5):
client.capture_to_memory(buffer_max=1)
# Reset to main resolution
time.sleep(0.5)
client.start_streaming()
client.change_streaming_mode(mode="default")
# Check after all of this the exposure time is the same.
assert client.exposure_time == set_time

View file

@ -9,13 +9,13 @@ from .cam_test_utils import camera_test_client
logging.basicConfig(level=logging.DEBUG)
def test_sensor_mode():
def test_streaming_mode():
"""Test capturing raw arrays in two different sensor modes."""
with camera_test_client() as client:
for size in [(3280, 2464), (1640, 1232)]:
client.sensor_mode = {"output_size": size, "bit_depth": 10}
arr = np.array(client.capture_array(stream_name="raw"))
for mode, res in ["default", (820, 616)], ["full_resolution", (3280, 2464)]:
client.change_streaming_mode(mode=mode)
arr = np.array(client.capture_array(stream_name="main"))
# Check that the array dimensions match the requested image size.
# Note: Numpy array shape is (y,x), but the sensor is set with (x,y)
# hence the need to compare index 0 with index 1.
assert arr.shape[0] == size[1]
assert arr.shape[0] == res[1]

View file

@ -6,7 +6,6 @@ on camera functionality using the simulation camera are in "test_camera".
from labthings_fastapi.testing import create_thing_without_server
from openflexure_microscope_server.things.camera import BaseCamera
from openflexure_microscope_server.things.camera.opencv import OpenCVCamera
from openflexure_microscope_server.things.camera.simulation import SimulatedCamera
@ -57,11 +56,9 @@ def test_thing_description_equivalence(mock_picam_thing):
camera child classes. Any addition of actions must be accompanied by an update
to this test, prompting discussion of whether the action belongs in the subclass
or the base camera class.
"""
base_td = create_thing_without_server(BaseCamera).thing_description()
base_actions = set(base_td.actions.keys())
base_props = set(base_td.properties.keys())
The base camera class is not instantiated as it is an Abstract Base Class
"""
sim_camera = create_thing_without_server(SimulatedCamera)
sim_description = _get_clean_camera_description(sim_camera)
opencv_camera = create_thing_without_server(OpenCVCamera)
@ -82,8 +79,8 @@ def test_thing_description_equivalence(mock_picam_thing):
# Camera actions and properties should generally be equivalent except for exposed
# manual settings and calibration actions.
assert opencv_actions == sim_actions == base_actions
assert opencv_props == sim_props == base_props
assert opencv_actions == sim_actions
assert opencv_props == sim_props
# For now PiCamera has a number of extra actions and properties. These should be
# reduced over time by creating a way to use the functionality in a way as clearly
@ -92,7 +89,6 @@ def test_thing_description_equivalence(mock_picam_thing):
picamera_extra_actions = {
"set_static_green_equalisation",
"set_ce_enable_to_off",
"stop_streaming",
"reset_ccm",
}
picamera_extra_props = {
@ -103,15 +99,12 @@ def test_thing_description_equivalence(mock_picam_thing):
"sensor_resolution",
"capture_metadata",
"camera_configuration",
"stream_resolution",
"tuning",
"sensor_modes",
"sensor_mode",
}
# Note these are only the action not exposed as calibration actions.
for action in picamera_extra_actions:
assert action in picamera_actions
for props in picamera_extra_props:
assert props in picamera_props
assert picamera_actions - base_actions == picamera_extra_actions
assert picamera_props - base_props == picamera_extra_props
assert picamera_actions - sim_actions == picamera_extra_actions
assert picamera_props - sim_props == picamera_extra_props

View file

@ -12,7 +12,6 @@ import labthings_fastapi as lt
from labthings_fastapi.testing import create_thing_without_server
from openflexure_microscope_server.things.background_detect import ChannelDeviationLUV
from openflexure_microscope_server.things.camera import BaseCamera
from openflexure_microscope_server.things.camera import (
picamera_tuning_file_utils as tf_utils,
)
@ -32,8 +31,8 @@ def temp_jpeg(tmp_path: Path) -> Path:
def test_add_metadata_to_capture(temp_jpeg):
"""Use a BaseCamera to add metadata to a tmp capture and test fields."""
base_cam = create_thing_without_server(BaseCamera)
"""Use a SimulatedCamerato add metadata to a tmp capture and test fields."""
cam = create_thing_without_server(SimulatedCamera)
metadata = {
"Dummy1": 1,
"Dummy2": "two",
@ -48,7 +47,7 @@ def test_add_metadata_to_capture(temp_jpeg):
"things_states": metadata,
}
base_cam._add_metadata_to_capture(str(temp_jpeg), capture_metadata)
cam._add_metadata_to_capture(str(temp_jpeg), capture_metadata)
# Reload EXIF
exif_dict = piexif.load(str(temp_jpeg))
@ -177,7 +176,7 @@ def test_picamera_metadata_written_to_exif(mock_picam_thing, temp_jpeg, mocker):
exif_dict = piexif.load(str(temp_jpeg))
user_comment = json.loads(exif_dict["Exif"][piexif.ExifIFD.UserComment].decode())
assert user_comment["camera"] == "StreamingPiCamera2"
assert user_comment["camera"] == "PiCameraV2"
assert user_comment["camera_board"] == "imx219"
# gamma_correction keys are cast to strings
assert user_comment["tuning"] == {

View file

@ -492,7 +492,7 @@ def check_run_scan(scan_thing, caplog, expected_exception=None):
final_scan_data = scan_thing._ongoing_scan.save_scan_data.call_args[0][0]
calls = {
"cam_start_streaming_calls": scan_thing._cam.start_streaming.call_count,
"cam_change_streaming_mode_calls": scan_thing._cam.change_streaming_mode.call_count,
"main_scan_loop_calls": scan_thing._main_scan_loop.call_count,
"return_to_start_calls": scan_thing._return_to_starting_position.call_count,
"perform_final_stitch_calls": scan_thing._perform_final_stitch.call_count,
@ -509,7 +509,7 @@ def test_run_scan(scan_thing_mocked_for_run_scan, caplog):
assert len(logs) == 0
expected_calls_numbers = {
"cam_start_streaming_calls": 2,
"cam_change_streaming_mode_calls": 2,
"main_scan_loop_calls": 1,
"return_to_start_calls": 1,
"perform_final_stitch_calls": 1,
@ -534,7 +534,7 @@ def test_run_scan_err_in_main_loop(scan_thing_mocked_for_run_scan, caplog, mocke
# Main loop not run, nor are return to start, final stitch, or purging of empty
# scans. Save scan data is still called twice
expected_calls_numbers = {
"cam_start_streaming_calls": 2,
"cam_change_streaming_mode_calls": 2,
"main_scan_loop_calls": 1,
"return_to_start_calls": 0,
"perform_final_stitch_calls": 0,
@ -559,7 +559,7 @@ def test_run_scan_cancelled(scan_thing_mocked_for_run_scan, caplog, mocker):
# Main loop not run, nor are return to start, final stitch, or purging of empty
# scans. Save scan data is still called twice
expected_calls_numbers = {
"cam_start_streaming_calls": 2,
"cam_change_streaming_mode_calls": 2,
"main_scan_loop_calls": 1,
"return_to_start_calls": 1,
"perform_final_stitch_calls": 1,
@ -584,7 +584,7 @@ def test_run_scan_fill_disk(scan_thing_mocked_for_run_scan, caplog, mocker):
# Main loop not run, nor are return to start, final stitch, or purging of empty
# scans. Save scan data is still called twice
expected_calls_numbers = {
"cam_start_streaming_calls": 2,
"cam_change_streaming_mode_calls": 2,
"main_scan_loop_calls": 1,
"return_to_start_calls": 0,
"perform_final_stitch_calls": 0,