Source code for thesis.workflows.registration.viewers

"""Viewer backends for registration quality control."""

from __future__ import annotations

import subprocess
from pathlib import Path
from typing import Sequence

from thesis.core.logging import get_logger

logger = get_logger(__name__)

__all__ = [
    "build_fsleyes_command",
    "describe_registration_viewer_command",
    "launch_registration_viewer",
]


[docs] def build_fsleyes_command( template_image: Path, warped_image: Path, overlay_opacity: float = 0.5, ) -> list[str]: """Build an FSLeyes command for template/overlay registration review.""" alpha = int(max(0.0, min(1.0, overlay_opacity)) * 100) return [ "fsleyes", str(template_image), str(warped_image), "-a", str(alpha), ]
def _spawn_detached(command: Sequence[str]) -> None: """Start a detached background process without blocking the workflow.""" subprocess.Popen( list(command), stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True, ) def _resolve_command( template_image: Path, warped_image: Path, backend: str, overlay_opacity: float, ) -> list[str]: """Validate the requested backend and build its viewer command.""" if backend == "html": raise NotImplementedError("HTML registration viewer backend is not implemented yet") if backend != "fsleyes": raise ValueError(f"Unsupported registration viewer backend: {backend}") return build_fsleyes_command(template_image, warped_image, overlay_opacity)
[docs] def describe_registration_viewer_command( template_image: Path, warped_image: Path, backend: str = "fsleyes", overlay_opacity: float = 0.5, ) -> str: """Return a shell-ready viewer command string for manual registration QC.""" command = _resolve_command(template_image, warped_image, backend, overlay_opacity) return " ".join(command)
[docs] def launch_registration_viewer( template_image: Path, warped_image: Path, backend: str = "fsleyes", overlay_opacity: float = 0.5, ) -> list[str]: """Launch the configured registration QC viewer and return its command.""" command = _resolve_command(template_image, warped_image, backend, overlay_opacity) logger.info("Launching registration viewer: {}", " ".join(command)) _spawn_detached(command) return command