class documentation

The base class for all cameras. All cameras must directly inherit from this class.

The connection to the camera hardware should be added to the __enter__ method not __init__ method of the subclass.

Method __enter__ Open hardware connection when the Thing context manager is opened.
Method __exit__ Close hardware connection when the Thing context manager is closed.
Method __init__ Initialise the base camera, this creates the background detectors.
Method background_detector_name The name of the active background selector.
Method background_detector_name.setter Validate and set background_detector_name.
Method capture Acquire one image from the camera.
Method capture_and_save_to_path Capture an image and save it to disk.
Method capture_as_array Acquire one image from the camera and return as an array.
Method capture_downsampled_array Acquire one image from the camera, downsample, and return as an array.
Method capture_to_memory Capture an image to memory. This can be saved later with save_from_memory.
Method change_streaming_mode Change the mode the camera is streaming in.
Method clear_buffers Clear all images in memory.
Method discard_frames Discard frames so that the next frame captured is fresh.
Method grab_as_array Acquire one image from the preview stream and return as an array.
Method grab_jpeg Acquire one image from the preview stream and return as blob of JPEG data.
Method grab_jpeg_size Acquire one image from the preview stream and return its size.
Method image_is_sample Label the current image as either background or sample.
Method kill_mjpeg_streams Kill the streams now as the server is shutting down.
Method record_framerate Record MJPEG stream framerate statistics.
Method save_from_memory Save an image that has been captured to memory.
Method set_background Grab an image, and use its statistics to set the background.
Method settle Sleep for the settling time, ready to provide a fresh frame.
Async Method snapshot Return a snapshot from the microscope.
Class Variable downsampled_array_factor The downsampling factor when calling capture_downsampled_array.
Class Variable lores_mjpeg_stream Undocumented
Class Variable mjpeg_stream Undocumented
Class Variable settling_time The settling time when calling the settle() method.
Class Variable streaming_mode Undocumented
Class Variable supported_image_formats Undocumented
Class Variable supports_focus_fom Undocumented
Property background_detector The active background detector instance.
Property calibration_required Whether the camera needs calibrating.
Property capture_modes Modes the camera can use for capturing.
Property focus_fom Return the focus figure of merit.
Property manual_camera_settings The camera settings to expose as property controls in the settings panel.
Property primary_calibration_actions The calibration actions for both calibration wizard and settings panel.
Property secondary_calibration_actions The calibration actions that appear only in settings panel.
Property stream_active Whether the MJPEG stream is active.
Property streaming_modes Modes the camera can stream in.
Property thing_state Return camera-specific metadata.
Method _add_metadata_to_capture Add the EXIF metadata for a JPEG image.
Method _capture_image Capture a PIL image from the camera.
Method _collect_ofm_metadata Return the metadata for a capture.
Async Method _monitor_framerate Asynchronously monitor the timing on incoming frames.
Method _start_streaming Start (or stop and restart) the camera.
Method _validate_capture_mode Check input capture mode exists, always returns a valid mode.
Class Variable _all_background_detectors Undocumented
Class Variable _class_settings Undocumented
Class Variable _memory_buffer Undocumented
Instance Variable _background_detector_name Undocumented
Instance Variable _default_background_detector Undocumented
Instance Variable _framerate_monitor_running Undocumented

Inherited from OFMThing:

Method create_data_path Create a RelativeDataPath object with this Thing set as the saving Thing.
Property data_dir The data directory for this thing.
Property show_data_in_gallery Whether to show in the Gallery.
Class Variable _show_data_in_gallery Undocumented
Instance Variable _data_dir Undocumented
def __exit__(self, _exc_type: type[BaseException], _exc_value: BaseException | None, _traceback: TracebackType | None): (source)
def __init__(self, thing_server_interface: lt.ThingServerInterface): (source)

Initialise the base camera, this creates the background detectors.

This must be run by all child camera classes.

To add a new background detector to the server it must be added to the dictionary in this function. Configuration will be added at a later date.

@lt.setting
def background_detector_name(self) -> str | None: (source)

The name of the active background selector.

def background_detector_name(self, name: str | None): (source)

Validate and set background_detector_name.

@lt.action
def capture(self, capture_mode: str = 'standard', image_format: str = 'jpeg', retain_image: bool = True) -> lt.blob.Blob: (source)

Acquire one image from the camera.

This will use the internal capture image functionally of _capture_image of the specific camera being used.

Parameters
capture_mode:strThe mode to use, must be one of capture_modes.
image_format:strThe image format to use, must be one of supported_image_formats
retain_image:bool(Default True) True to save image to the microscope, False to only save temporarily for transfer.
Returns
lt.blob.BlobA LabThings Blob that with access to the captured file.
def capture_and_save_to_path(self, path: RelativeDataPath, capture_mode: str = 'standard'): (source)

Capture an image and save it to disk.

This is not an action as it exposes a direct path for saving

Parameters
path:RelativeDataPathThe path to save the file to, this should be a RelativeDataPath object. If the saving Thing is not set for the path, the camera's data directory will be used.
capture_mode:str(Optional) The name of the capture mode as defined by the camera.
@abstractmethod
@lt.action
def capture_as_array(self, capture_mode: str = 'standard', raw: bool = False) -> NDArray: (source)
@lt.action
def capture_downsampled_array(self) -> NDArray: (source)

Acquire one image from the camera, downsample, and return as an array.

  • The array is downsampled by the thing property downsampled_array_factor.
  • The default capture array arguments are used.

This method provides the interface expected by the camera_stage_mapping.

@lt.action
def capture_to_memory(self, capture_mode: str = 'standard', buffer_max: int = 1, max_attempts: int = 5) -> int: (source)

Capture an image to memory. This can be saved later with save_from_memory.

Note that only one image is held in memory so this will overwrite any image in memory.

Parameters
capture_mode:strUndocumented
buffer_max:intThe maximum number of images that should be in the buffer once this images is added. Default is 1.
max_attempts:intThe maximum number of times to attempt the capture.
Returns
intthe buffer id of the image captured
@lt.action
def change_streaming_mode(self, mode: str = 'default'): (source)

Change the mode the camera is streaming in.

When creating a subclass. Subclass the method _start_streaming rather than this method.

Parameters
mode:strMust be a key from streaming_modes
@lt.action
def clear_buffers(self): (source)

Clear all images in memory.

@lt.action
def grab_as_array(self, stream_name: Literal['main', 'lores'] = 'main') -> NDArray: (source)

Acquire one image from the preview stream and return as an array.

It works like grab_jpeg but reliably handles broken streams. Prefer using this method over directly grabbing the frame and converting to a numpy array via PIL.

This differs from capture_as_array in that it does not pause the MJPEG preview stream.

@lt.action
def grab_jpeg(self, stream_name: Literal['main', 'lores'] = 'main') -> lt.blob.Blob: (source)

Acquire one image from the preview stream and return as blob of JPEG data.

Note: in rare cases the JPEG stream may be broken. This can cause an OS error when loading the image. If loading with PIL, as long as the header data is complete, this error will not be raised until the data is accessed. Consider using grab_jpeg_as_array instead.

This differs from capture in that it does not pause the MJPEG preview stream. Instead, we simply return the next frame from that stream (either "main" for the preview stream, or "lores" for the low resolution preview). No metadata is returned.

@lt.action
def grab_jpeg_size(self, stream_name: Literal['main', 'lores'] = 'main') -> int: (source)

Acquire one image from the preview stream and return its size.

@lt.action
def image_is_sample(self) -> tuple[bool, str]: (source)

Label the current image as either background or sample.

def kill_mjpeg_streams(self): (source)

Kill the streams now as the server is shutting down.

This is called when uvicorn gets the a shutdown signal. As this is called from the event loop it cannot interact with the our ThingProperties or run self.mjpeg_stream.stop() as the portal cannot be called from this loop.

Instead we just set the _streaming value to False. This stops the async frame generator when the next frame notifies.

@lt.action
def record_framerate(self, duration: float = 5.0) -> str: (source)

Record MJPEG stream framerate statistics.

@lt.action
def save_from_memory(self, path: RelativeDataPath, buffer_id: int | None = None): (source)

Save an image that has been captured to memory.

Note this is not exposed as an action as it allows arbitrary paths on disk to be written to.

Parameters
path:RelativeDataPathThe path to save the file to
buffer_id:int | NoneThe buffer id of the image to save, this was returned by capture_to_memory
@lt.action
def set_background(self): (source)

Grab an image, and use its statistics to set the background.

This should be run when the microscope is looking at an empty region, and will calculate the mean and standard deviation of the pixel values in the LUV colourspace. These values will then be used to compare future images to the distribution, to determine if each pixel is foreground or background.

@lt.action
def settle(self): (source)

Sleep for the settling time, ready to provide a fresh frame.

This function will sleep for the given time, and clear the buffer after sleeping. As such, the next frame captured from the camera after running this function will always be captured after settling.

This method provides the interface expected by the camera_stage_mapping.

@lt.endpoint('get', 'snapshot', responses={200: {'description': 'A snapshot of the microscope stream', 'content': {'image/jpeg': {}}}})
async def snapshot(self) -> Response: (source)

Return a snapshot from the microscope.

downsampled_array_factor: int = (source)

The downsampling factor when calling capture_downsampled_array.

lores_mjpeg_stream = (source)

Undocumented

mjpeg_stream = (source)

Undocumented

settling_time: float = (source)

The settling time when calling the settle() method.

supported_image_formats = (source)

Undocumented

@property
background_detector: BackgroundDetectAlgorithm | None = (source)

The active background detector instance.

@lt.property
calibration_required: bool = (source)

Whether the camera needs calibrating.

This always returns False in BaseCamera. It should be reimplemented by child classes if calibration is required.

@lt.property
capture_modes: Mapping[str, CaptureMode] = (source)

Modes the camera can use for capturing.

@property
focus_fom: int = (source)

Return the focus figure of merit.

This returns a NotImplementedError if not supported by the camera. To use, requires self.supports_focus_fom to be set to True.

@lt.property
primary_calibration_actions: list[ActionButton] = (source)
@lt.property
secondary_calibration_actions: list[ActionButton] = (source)
@lt.property
streaming_modes: Mapping[str, StreamingMode] = (source)

Modes the camera can stream in.

@property
thing_state: Mapping[str, Any] = (source)

Return camera-specific metadata.

By default, this just adds the subclass name as the camera type. Subclasses can extend by overriding this property and calling super().thing_state.

def _add_metadata_to_capture(self, path: str, capture_metadata: dict): (source)

Add the EXIF metadata for a JPEG image.

This adds: - UserComment (JSON-encoded metadata from the Things) - Capture time (DateTimeOriginal, DateTimeDigitized, 0th DateTime) - Camera Make and Model

@abstractmethod
def _capture_image(self, capture_mode: str = 'standard') -> Image.Image: (source)

Capture a PIL image from the camera.

This unlike the grab_* methods this may pause the stream or temporarily switch streaming mode to capture the image if required by the mode.

def _collect_ofm_metadata(self) -> dict: (source)

Return the metadata for a capture.

This is information from the thing states, the time, and make/model names.

async def _monitor_framerate(self, duration: float, sample_interval: float = 0.1) -> tuple[float, int, list[dict[str, float | int]]]: (source)

Asynchronously monitor the timing on incoming frames.

def _validate_capture_mode(self, capture_mode: str) -> str: (source)

Check input capture mode exists, always returns a valid mode.

Parameters
capture_mode:strThe capture mode to check. If this isn't valid a warning will be logged.
Returns
strThe input capture mode if it is supported, or "standard".
_all_background_detectors: Mapping[str, BackgroundDetectAlgorithm] = (source)

Undocumented

_class_settings: dict[str, bool] = (source)

Undocumented

_memory_buffer = (source)

Undocumented

_background_detector_name: str | None = (source)

Undocumented

_default_background_detector: str = (source)

Undocumented

_framerate_monitor_running: bool = (source)

Undocumented