@@ -48,6 +48,53 @@ def run(self) -> None:
4848 )
4949
5050
51+ @dataclass
52+ class Animate :
53+ """Create an animated GIF or MP4 sweeping through slices.
54+
55+ The output format is inferred from the file extension:
56+ ``.gif`` produces an animated GIF, ``.mp4`` produces a video.
57+
58+ Examples::
59+
60+ torchio animate brain.nii.gz brain.gif
61+ torchio animate brain.nii.gz brain.mp4 --seconds 10 --direction S
62+ """
63+
64+ path : Annotated [Path , tyro .conf .Positional ]
65+ """Path to the input image."""
66+
67+ output : Annotated [Path , tyro .conf .Positional ]
68+ """Output path (.gif or .mp4)."""
69+
70+ seconds : float = 5.0
71+ """Duration of the animation in seconds."""
72+
73+ direction : str = "I"
74+ """Anatomical sweep direction (I, S, A, P, R, or L)."""
75+
76+ def run (self ) -> None :
77+ image = tio .ScalarImage (self .path )
78+ suffix = self .output .suffix .lower ()
79+ if suffix == ".gif" :
80+ image .to_gif (
81+ self .output ,
82+ seconds = self .seconds ,
83+ direction = self .direction ,
84+ )
85+ elif suffix == ".mp4" :
86+ image .to_video (
87+ self .output ,
88+ seconds = self .seconds ,
89+ direction = self .direction ,
90+ )
91+ else :
92+ msg = f"Unsupported output format { self .output .suffix !r} . Use .gif or .mp4."
93+ print (msg , file = sys .stderr )
94+ sys .exit (1 )
95+ print (f"Created { self .output } " )
96+
97+
5198@dataclass
5299class Info :
53100 """Print image metadata to stdout."""
@@ -162,7 +209,7 @@ def run(self) -> None:
162209 self .command .run ()
163210
164211
165- Command = Union [Plot , Info , Convert , Transform , Cache ] # noqa: UP007 (tyro needs Union)
212+ Command = Union [Plot , Animate , Info , Convert , Transform , Cache ] # noqa: UP007 (tyro needs Union)
166213
167214
168215# ---------------------------------------------------------------------------
0 commit comments