Source code for magscope.utils
from __future__ import annotations
from datetime import datetime
from enum import IntEnum, StrEnum
from typing import TYPE_CHECKING, Callable, Type
import magtrack
import numpy as np
from PyQt6.QtGui import QImage
from magscope.ipc_commands import Command
[docs]
class AcquisitionMode(StrEnum):
""" Enum for the different acquisition modes """
[docs]
TRACK_AND_CROP_VIDEO = 'track & video (cropped)'
[docs]
TRACK_AND_FULL_VIDEO = 'track & video (full)'
[docs]
CROP_VIDEO = 'video (cropped)'
[docs]
FULL_VIDEO = 'video (full)'
[docs]
def crop_stack_to_rois(stack, rois):
rois = np.asarray(rois, dtype=np.int64)
# Pre-allocate space for cropped_stack
n_images = stack.shape[2]
n_rois = len(rois)
width = rois[0, 1] - rois[0, 0]
shape = (width, width, n_images, n_rois)
cropped_stack = np.ndarray(
shape, dtype=stack.dtype
) # width, width, frames, rois
# Crop
for i, roi in enumerate(rois):
cropped_stack[:, :, :, i] = (
stack[roi[0]:roi[1], roi[2]:roi[3], :]
)
return cropped_stack
[docs]
def numpy_type_to_qt_image_type(numpy_type):
NP2QT = {
np.uint8: QImage.Format.Format_Grayscale8,
np.uint16: QImage.Format.Format_Grayscale16
}
if numpy_type not in NP2QT:
raise ValueError(f"Unsupported bit type: {numpy_type}")
return NP2QT[numpy_type]
[docs]
def date_timestamp_str(timestamp):
date_str = datetime.today().strftime('%Y-%m-%d')
hour = (timestamp // 3600 % 24 - 5) % 24
minutes = timestamp // 60 % 60
seconds = timestamp // 1 % 60
milliseconds = timestamp % 1 * 1000
return f'{date_str} {hour:02.0f}-{minutes:02.0f}-{seconds:02.0f}.{milliseconds:03.0f}'
[docs]
class PoolVideoFlag(IntEnum):
[docs]
class Units:
# Meters
# Newtons
# Seconds
sec = s = 1.
# Directions
clockwise = cw = 1.
counterclockwise = ccw = -1.
[docs]
def register_script_command(command_type: type[Command]):
"""Decorator marking a method as callable from a MagScope script.
Each script command must be paired with the IPC :class:`~magscope.ipc_commands.Command`
that will be dispatched when the script executes that step. The decorator mirrors
:func:`magscope.ipc_commands.command_handler` by attaching metadata to the wrapped
function without constraining how it is collected.
"""
def decorator(meth: callable):
meth._scriptable = True
meth._script_command_type = command_type
return meth
return decorator
[docs]
def check_cupy() -> bool:
"""Return ``True`` when the CuPy package is usable."""
return magtrack.check_cupy()