magscope.videoprocessing
========================

.. py:module:: magscope.videoprocessing


Attributes
----------

.. autoapisummary::

   magscope.videoprocessing.ValueTypeUI8
   magscope.videoprocessing.logger
   magscope.videoprocessing._LOOKUP_Z_PROFILE_WARNING
   magscope.videoprocessing._DEFAULT_TRACKING_OPTIONS


Classes
-------

.. autoapisummary::

   magscope.videoprocessing.VideoProcessorManager
   magscope.videoprocessing.VideoWorker


Module Contents
---------------

.. py:data:: ValueTypeUI8

.. py:data:: logger

.. py:data:: _LOOKUP_Z_PROFILE_WARNING
   :value: 'lookup_z_profile_size_warning'


.. py:data:: _DEFAULT_TRACKING_OPTIONS

.. py:class:: VideoProcessorManager

   Bases: :py:obj:`magscope.processes.ManagerProcessBase`


   Abstract base class for processes in the MagScope

   Subclass requirements:
   * Each subclass should have a unique name.
   * There should only be one instance of each subclass (singleton).
   * The class name is used for consistent inter-process identification.


   .. py:attribute:: _tasks
      :type:  multiprocessing.queues.Queue | None
      :value: None



   .. py:attribute:: _n_workers
      :type:  int | None
      :value: None



   .. py:attribute:: _workers
      :type:  list[VideoWorker]
      :value: []



   .. py:attribute:: _gpu_lock
      :type:  multiprocessing.synchronize.Lock


   .. py:attribute:: _profile_length_queue
      :type:  multiprocessing.queues.Queue | None
      :value: None



   .. py:attribute:: _pending_profile_length_request
      :value: False



   .. py:attribute:: _warning_queue
      :type:  multiprocessing.queues.Queue | None
      :value: None



   .. py:attribute:: _zlut_capture_complete_queue
      :type:  multiprocessing.queues.Queue | None
      :value: None



   .. py:attribute:: _zlut_capture_earliest_timestamp
      :type:  float | None
      :value: None



   .. py:attribute:: _zlut_capture_motor_z_value
      :type:  float | None
      :value: None



   .. py:attribute:: _zlut_capture_remaining_profiles_per_bead
      :type:  int | None
      :value: None



   .. py:attribute:: _zlut_capture_step_index
      :type:  int | None
      :value: None



   .. py:attribute:: _zlut_frozen_bead_ids


   .. py:attribute:: _zlut_frozen_bead_rois


   .. py:attribute:: _zlut_profile_length_queue
      :type:  multiprocessing.queues.Queue | None
      :value: None



   .. py:attribute:: _pending_zlut_profile_length_request
      :value: False



   .. py:attribute:: _lookup_z_warning_reported
      :value: False



   .. py:attribute:: _waiting_for_acquisition
      :type:  bool | None
      :value: None



   .. py:attribute:: _save_profiles
      :value: False



   .. py:attribute:: _zlut_path
      :type:  pathlib.Path | None


   .. py:attribute:: _zlut_metadata
      :type:  dict[str, float | int] | None
      :value: None



   .. py:attribute:: _zlut
      :value: None



   .. py:attribute:: _tracking_options
      :type:  dict


   .. py:method:: set_settings(settings: magscope.settings.MagScopeSettings)


   .. py:method:: update_tracking_options(value: dict)


   .. py:method:: setup()


   .. py:method:: do_main_loop()


   .. py:method:: _try_reserve_processing_stack() -> bool


   .. py:method:: _release_reserved_processing_stack() -> None


   .. py:method:: _stack_coordination_lock()


   .. py:method:: quit()

      Shutdown the process (and ask the other processes to quit too).



   .. py:method:: load_zlut_file(filepath: str) -> None


   .. py:method:: _load_default_zlut() -> None


   .. py:method:: unload_zlut() -> None


   .. py:method:: _clear_zlut_state() -> None


   .. py:method:: _set_zlut_from_path(path: pathlib.Path) -> None


   .. py:method:: _extract_zlut_metadata(zlut_array: numpy.ndarray) -> dict[str, float | int]
      :staticmethod:



   .. py:method:: _to_processing_array(zlut_array: numpy.ndarray)
      :staticmethod:



   .. py:method:: _broadcast_zlut_metadata() -> None


   .. py:method:: _notify_zlut_error(path: pathlib.Path, exc: Exception) -> None


   .. py:method:: report_profile_length() -> None

      Arm a one-shot profile-length report for a future processed frame.

      The request intentionally rides along with the normal worker task queue
      instead of probing the current ``VideoBuffer`` contents immediately.
      This keeps the result tied to video processed after the request arrives
      and ensures only one worker handles the request at a time via a normal
      task-local flag.



   .. py:method:: report_zlut_profile_length(bead_ids: tuple[int, Ellipsis] = (), bead_rois: tuple[tuple[int, int, int, int], Ellipsis] = ()) -> None


   .. py:method:: _process_profile_length_reports() -> None

      Forward the first successful worker measurement back to the UI.

      Workers only enqueue successful measurements, so leaving the pending
      flag armed causes later normal processing tasks to keep carrying the
      request until one succeeds.



   .. py:method:: _process_zlut_profile_length_reports() -> None


   .. py:method:: clear_pending_zlut_profile_length_request() -> None


   .. py:method:: arm_zlut_sweep_capture(step_index: int, motor_z_value: float, remaining_profiles_per_bead: int, earliest_timestamp: float, bead_ids: tuple[int, Ellipsis] = (), bead_rois: tuple[tuple[int, int, int, int], Ellipsis] = ()) -> None


   .. py:method:: disarm_zlut_sweep_capture() -> None


   .. py:method:: _process_zlut_capture_reports() -> None


   .. py:method:: _add_task()


   .. py:method:: _set_zlut_frozen_rois(*, bead_ids: tuple[int, Ellipsis], bead_rois: tuple[tuple[int, int, int, int], Ellipsis]) -> None


   .. py:method:: _should_use_frozen_zlut_rois() -> bool


   .. py:method:: _process_worker_warnings() -> None


   .. py:method:: script_wait_until_acquisition_on(value: bool)


   .. py:method:: _finish_waiting_when_ready()


.. py:class:: VideoWorker(tasks: multiprocessing.queues.Queue, locks: dict[str, multiprocessing.synchronize.Lock], reserved_stacks: ValueTypeUI32, completed_stacks: ValueTypeUI64, busy_count: ValueTypeUI8, gpu_lock: multiprocessing.Lock, profile_length_queue: multiprocessing.queues.Queue | None, warning_queue: multiprocessing.queues.Queue | None, zlut_capture_complete_queue: multiprocessing.queues.Queue | None, zlut_profile_length_queue: multiprocessing.queues.Queue | None, live_profile_enabled: ValueTypeUI8, live_profile_bead: ValueTypeInt)

   Bases: :py:obj:`multiprocessing.Process`


   Process objects represent activity that is run in a separate process

   The class is analogous to `threading.Thread`


   .. py:attribute:: _gpu_lock
      :type:  multiprocessing.Lock


   .. py:attribute:: _tasks
      :type:  multiprocessing.queues.Queue


   .. py:attribute:: _locks
      :type:  dict[str, multiprocessing.synchronize.Lock]


   .. py:attribute:: _reserved_stacks
      :type:  ValueTypeUI32


   .. py:attribute:: _completed_stacks
      :type:  ValueTypeUI64


   .. py:attribute:: _busy_count
      :type:  ValueTypeUI8


   .. py:attribute:: _profile_length_queue
      :type:  multiprocessing.queues.Queue | None


   .. py:attribute:: _warning_queue
      :type:  multiprocessing.queues.Queue | None


   .. py:attribute:: _zlut_capture_complete_queue
      :type:  multiprocessing.queues.Queue | None


   .. py:attribute:: _zlut_profile_length_queue
      :type:  multiprocessing.queues.Queue | None


   .. py:attribute:: _live_profile_enabled


   .. py:attribute:: _live_profile_bead


   .. py:attribute:: _video_buffer
      :type:  magscope.datatypes.VideoBuffer | None
      :value: None



   .. py:attribute:: _tracks_buffer
      :type:  magscope.datatypes.MatrixBuffer | None
      :value: None



   .. py:attribute:: _task_owes_reserved_stack
      :value: False



   .. py:attribute:: _zlut_sweep_dataset
      :type:  magscope.datatypes.ZLUTSweepDataset | None
      :value: None



   .. py:method:: run()

      Method to be run in sub-process; can be overridden in sub-class



   .. py:method:: _release_reserved_stack_if_pending() -> None


   .. py:method:: _stack_coordination_lock()


   .. py:method:: _report_zlut_capture_task_failure(task: dict | None, exc: Exception) -> None


   .. py:method:: _report_zlut_capture_task_retry(zlut_capture: dict | None) -> None


   .. py:method:: process(kwargs)


   .. py:method:: _notify_lookup_profile_warning(warning_records: list[warnings.WarningMessage]) -> None


   .. py:method:: _release_stack()


