Files
navigate/test/model/devices/camera/test_camera_synthetic.py
2025-12-04 16:07:30 +08:00

194 lines
7.5 KiB
Python

# Copyright (c) 2021-2025 The University of Texas Southwestern Medical Center.
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted for academic and research use only (subject to the
# limitations in the disclaimer below) provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
# NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
# THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Third Party Imports
import pytest
import numpy as np
from navigate.model.devices.camera.synthetic import (
SyntheticCamera,
SyntheticCameraController,
)
@pytest.fixture(scope="class")
def synthetic_camera(dummy_model):
dummy_model = dummy_model
scc = SyntheticCameraController()
microscope_name = dummy_model.configuration["experiment"]["MicroscopeState"][
"microscope_name"
]
synthetic_camera = SyntheticCamera(microscope_name, scc, dummy_model.configuration)
return synthetic_camera
class TestSyntheticCamera:
"""Unit Test for Camera Synthetic Class"""
@pytest.fixture(autouse=True)
def _prepare_camera(self, synthetic_camera):
self.synthetic_camera = synthetic_camera
def test_synthetic_camera_attributes(self):
desired_attributes = [
"x_pixels",
"y_pixels",
"is_acquiring",
"_mean_background_count",
"_noise_sigma",
"camera_controller",
"current_frame_idx",
"data_buffer",
"num_of_frame",
"pre_frame_idx",
]
for da in desired_attributes:
assert hasattr(self.synthetic_camera, da)
def test_synthetic_camera_wheel_attributes_type(self):
desired_attributes = {
"x_pixels": int,
"y_pixels": int,
"is_acquiring": bool,
"_mean_background_count": int,
"_noise_sigma": np.float64,
# 'current_frame_idx': None,
# 'data_buffer': None,
# 'num_of_frame': None,
# 'pre_frame_idx': None,
}
for key in desired_attributes:
attribute = getattr(self.synthetic_camera, key)
print(key, type(attribute), desired_attributes[key])
assert type(attribute) == desired_attributes[key]
def test_synthetic_camera_methods(self):
methods = [
"report_settings",
"close_camera",
"set_sensor_mode",
"set_exposure_time",
"set_line_interval",
"set_binning",
"initialize_image_series",
"close_image_series",
"generate_new_frame",
"get_new_frame",
"set_ROI",
]
for m in methods:
assert hasattr(self.synthetic_camera, m) and callable(
getattr(self.synthetic_camera, m)
)
def test_synthetic_camera_wheel_method_calls(self):
self.synthetic_camera.report_settings()
self.synthetic_camera.close_camera()
self.synthetic_camera.set_sensor_mode(mode="test")
self.synthetic_camera.set_exposure_time(exposure_time=0.2)
self.synthetic_camera.set_line_interval(line_interval_time=1)
self.synthetic_camera.set_binning(binning_string="2x2")
self.synthetic_camera.initialize_image_series()
self.synthetic_camera.close_image_series()
self.synthetic_camera.get_new_frame()
self.synthetic_camera.set_ROI()
def test_synthetic_camera_exposure(self):
exposure_time = 200
self.synthetic_camera.set_exposure_time(exposure_time=exposure_time / 1000)
assert (exposure_time / 1000) == self.synthetic_camera.camera_exposure_time
def test_synthetic_camera_binning(self):
x_pixels = self.synthetic_camera.x_pixels
self.synthetic_camera.set_binning(binning_string="2x2")
assert self.synthetic_camera.x_binning == 2
assert self.synthetic_camera.y_binning == 2
assert type(self.synthetic_camera.x_binning) == int
assert type(self.synthetic_camera.y_binning) == int
assert self.synthetic_camera.x_pixels == x_pixels / 2
def test_synthetic_camera_initialize_image_series(self):
self.synthetic_camera.initialize_image_series()
assert self.synthetic_camera.num_of_frame == 100
assert self.synthetic_camera.data_buffer is None
assert self.synthetic_camera.current_frame_idx == 0
assert self.synthetic_camera.pre_frame_idx == 0
assert self.synthetic_camera.is_acquiring is True
def test_synthetic_camera_close_image_series(self):
self.synthetic_camera.close_image_series()
assert self.synthetic_camera.pre_frame_idx == 0
assert self.synthetic_camera.current_frame_idx == 0
assert self.synthetic_camera.is_acquiring is False
def test_synthetic_camera_acquire_images(self):
import random
from navigate.model.concurrency.concurrency_tools import SharedNDArray
number_of_frames = 100
data_buffer = [
SharedNDArray(shape=(2048, 2048), dtype="uint16")
for i in range(number_of_frames)
]
self.synthetic_camera.initialize_image_series(data_buffer, number_of_frames)
assert self.synthetic_camera.is_acquiring is True, "should be acquring"
frame_idx = 0
for i in range(10):
frame_num = random.randint(1, 30)
for j in range(frame_num):
self.synthetic_camera.generate_new_frame()
frames = self.synthetic_camera.get_new_frame()
assert len(frames) == frame_num, "frame number isn't right!"
assert frames[0] == frame_idx, "frame idx isn't right!"
frame_idx = (frame_idx + frame_num) % number_of_frames
self.synthetic_camera.close_image_series()
assert (
self.synthetic_camera.is_acquiring is False
), "is_acquiring should be False"
def test_synthetic_camera_set_roi(self):
self.synthetic_camera.set_ROI()
assert self.synthetic_camera.x_pixels == 2048
assert self.synthetic_camera.y_pixels == 2048
self.synthetic_camera.set_ROI(roi_height=500, roi_width=700)
assert self.synthetic_camera.x_pixels == 700
assert self.synthetic_camera.y_pixels == 500