titi commited on
Commit
2530008
·
1 Parent(s): fe43e6c

now supports url parameters and example in the app

Browse files
Files changed (2) hide show
  1. README.md +40 -15
  2. app.py +118 -38
README.md CHANGED
@@ -1,23 +1,9 @@
1
- ---
2
- title: Pystackreg Web App
3
- emoji: 🧠
4
- colorFrom: indigo
5
- colorTo: blue
6
- sdk: gradio
7
- sdk_version: 5.25.1
8
- app_file: app.py
9
- pinned: false
10
- tags:
11
- - image-processing
12
- - registration
13
- - pystackreg
14
- ---
15
  # 🧠 Stack Image Registration Web App
16
  A web-based application for image stack registration powered by **Gradio** and **pystackreg**.
17
  This tool allows users to align and stabilize multi-frame TIFF images using a variety of transformation models.
18
 
19
  <p align="center">
20
- <img src="https://raw.githubusercontent.com/qchapp/pystackreg-app/refs/heads/master/images/app.png" height="500">
21
  </p>
22
 
23
  ---
@@ -83,6 +69,45 @@ Each mode offers:
83
 
84
  ---
85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  ### 📚 Credits
87
 
88
  - **App Author**: [Quentin Chappuis](https://github.com/qchapp)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # 🧠 Stack Image Registration Web App
2
  A web-based application for image stack registration powered by **Gradio** and **pystackreg**.
3
  This tool allows users to align and stabilize multi-frame TIFF images using a variety of transformation models.
4
 
5
  <p align="center">
6
+ <img src="images/app.png" height="500">
7
  </p>
8
 
9
  ---
 
69
 
70
  ---
71
 
72
+ ### 📂 Examples in the App
73
+
74
+ You can try the application directly using preloaded examples from the [`pystackreg`](https://github.com/glichtner/pystackreg) repository.
75
+ Each mode includes interactive buttons that load demo TIFF stacks automatically:
76
+
77
+ - 📚 **Reference-Based Alignment**:
78
+ Loads a stack of PC12 microscopy frames.
79
+
80
+ - 🎯 **Stack-Based Alignment**:
81
+ Loads both an unregistered and a translation-aligned stack.
82
+
83
+ - 🧩 **Frame-to-Frame Alignment**:
84
+ Uses the same unregistered stack for aligning specific frames.
85
+
86
+ No need to upload your own files — just click and experiment!
87
+
88
+ ---
89
+
90
+ ### 🌐 URL Parameter Support
91
+
92
+ The app supports loading image stacks from external URLs using query parameters.
93
+
94
+ **▶️ Load a single stack (for Reference-Based or Frame-to-Frame):**
95
+
96
+ ```
97
+ https://huggingface.co/spaces/qchapp/pystackreg-app?file_url=https://github.com/glichtner/pystackreg/raw/master/examples/data/pc12-unreg.tif
98
+ ```
99
+
100
+
101
+ **▶️ Load two stacks (for Stack-Based Alignment):**
102
+
103
+ ```
104
+ https://huggingface.co/spaces/qchapp/pystackreg-app?file_url_1=https://github.com/glichtner/pystackreg/raw/master/examples/data/pc12-unreg.tif&file_url_2=https://github.com/glichtner/pystackreg/raw/master/examples/data/pc12-reg-translation.tif
105
+ ```
106
+
107
+ > 💡 The app will automatically load and preview the provided stack(s) in the appropriate tabs.
108
+
109
+ ---
110
+
111
  ### 📚 Credits
112
 
113
  - **App Author**: [Quentin Chappuis](https://github.com/qchapp)
app.py CHANGED
@@ -5,6 +5,7 @@ from pystackreg import StackReg
5
  import imageio.v2 as iio
6
  import tifffile
7
  import tempfile
 
8
 
9
  from core.utils import *
10
 
@@ -12,38 +13,34 @@ from core.utils import *
12
  original_frames, aligned_frames = [], []
13
  ref_frames, mov_frames, reg_frames = [], [], []
14
  custom_stack, reg_result = [], None
15
- full_stack, full_aligned = [], []
16
 
17
- # reset
18
  def reset_intra_stack():
19
  global original_frames, aligned_frames
20
  original_frames, aligned_frames = [], []
21
- return [None, gr.update(value=0, minimum=0, maximum=0), None, gr.update(value=0, minimum=0, maximum=0), None, gr.update(value=0, minimum=0, maximum=0), None, gr.update(value=0, minimum=0, maximum=0), None]
 
22
 
23
  def reset_reference_based():
24
  global ref_frames, mov_frames, reg_frames
25
  ref_frames, mov_frames, reg_frames = [], [], []
26
- return [None, None, None, gr.update(value=0, minimum=0, maximum=0), None, gr.update(value=0, minimum=0, maximum=0), None]
 
27
 
28
  def reset_frame_to_frame():
29
  global custom_stack, reg_result
30
  custom_stack, reg_result = [], None
31
- return [None, gr.update(value=0, minimum=0, maximum=0), gr.update(value=0, minimum=0, maximum=0), None, None]
 
32
 
33
-
34
- # Registration Logic
35
  def intra_stack_align(f, ref_idx, ext_file, ext_idx, mode):
36
  global original_frames, aligned_frames
37
  stack = load_stack(f)
38
  original_frames = [Image.fromarray(fr) for fr in stack]
39
  sr = StackReg(get_sr_mode(mode))
40
 
41
- if ext_file:
42
- ext_stack = load_stack(ext_file)
43
- ref = ext_stack[ext_idx]
44
- else:
45
- ref = stack[ref_idx]
46
-
47
  aligned = [sr.register_transform(ref, fr) for fr in stack]
48
  aligned = normalize_stack(np.stack(aligned))
49
  aligned_frames = [upscale(Image.fromarray(fr)) for fr in aligned]
@@ -52,11 +49,8 @@ def intra_stack_align(f, ref_idx, ext_file, ext_idx, mode):
52
  tifffile.imwrite(path, aligned, photometric='minisblack')
53
 
54
  return (
55
- original_frames[0],
56
- gr.update(value=0, maximum=len(original_frames) - 1),
57
- aligned_frames[0],
58
- gr.update(value=0, maximum=len(aligned_frames) - 1),
59
- path
60
  )
61
 
62
  def reference_align(ref_file, mov_file, mode):
@@ -65,10 +59,12 @@ def reference_align(ref_file, mov_file, mode):
65
  mov_stack = load_stack(mov_file)
66
  ref_frames = [Image.fromarray(f) for f in ref_stack]
67
  mov_frames = [Image.fromarray(f) for f in mov_stack]
 
68
  sr = StackReg(get_sr_mode(mode))
69
  aligned = [sr.register_transform(ref_stack[0], f) for f in mov_stack]
70
  aligned = normalize_stack(np.stack(aligned))
71
  reg_frames = [upscale(Image.fromarray(f)) for f in aligned]
 
72
  path = tempfile.NamedTemporaryFile(suffix=".tif", delete=False).name
73
  tifffile.imwrite(path, aligned, photometric='minisblack')
74
  return ref_frames[0], gr.update(value=0, maximum=len(ref_frames)-1), \
@@ -78,14 +74,28 @@ def frame_to_frame_align(file, ref_idx, mov_idx, mode):
78
  global custom_stack, reg_result
79
  stack = load_stack(file)
80
  custom_stack = [Image.fromarray(f) for f in stack]
 
81
  sr = StackReg(get_sr_mode(mode))
82
  aligned = sr.register_transform(stack[ref_idx], stack[mov_idx])
83
  aligned = normalize_stack(np.stack([aligned]))[0]
84
  reg_result = Image.fromarray(aligned)
 
85
  path = tempfile.NamedTemporaryFile(suffix=".tif", delete=False).name
86
  tifffile.imwrite(path, aligned[np.newaxis, ...], photometric='minisblack')
87
  return reg_result, path
88
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  # Interface
91
  with gr.Blocks() as demo:
@@ -100,16 +110,24 @@ with gr.Blocks() as demo:
100
  file_input = gr.File(label="Upload Stack to Register")
101
  use_ext_ref = gr.Checkbox(label="Use external reference stack")
102
 
 
 
 
 
 
 
 
 
103
  with gr.Row():
104
  ref_slider = gr.Slider(label="Reference Frame (from uploaded stack)", minimum=0, maximum=0, value=0, step=1, visible=True)
105
  ext_ref_file = gr.File(label="Upload External Reference Stack (.tif)", visible=False)
106
  ext_ref_slider = gr.Slider(label="Reference Frame (from external stack)", minimum=0, maximum=0, value=0, step=1, visible=False)
107
 
108
  use_ext_ref.change(
109
- lambda use_ext: (
110
- gr.update(visible=not use_ext),
111
- gr.update(visible=use_ext),
112
- gr.update(visible=use_ext)
113
  ),
114
  use_ext_ref,
115
  [ref_slider, ext_ref_file, ext_ref_slider]
@@ -122,11 +140,11 @@ with gr.Blocks() as demo:
122
  )
123
 
124
  with gr.Row():
125
- show_advanced = gr.Checkbox(label="Show Advanced Settings", value=False)
126
  mode_dropdown = gr.Dropdown(["TRANSLATION", "RIGID_BODY", "SCALED_ROTATION", "AFFINE", "BILINEAR"],
127
- value="RIGID_BODY", label="Transformation Mode", visible=False)
128
 
129
- show_advanced.change(lambda v: gr.update(visible=v), show_advanced, mode_dropdown)
130
  run_btn = gr.Button("▶️ Align Stack")
131
 
132
  with gr.Row():
@@ -151,11 +169,12 @@ with gr.Blocks() as demo:
151
  [original_image, original_slider, aligned_image, aligned_slider, download]
152
  )
153
 
154
- original_slider.change(lambda i: original_frames[i] if 0 <= i < len(original_frames) else None, original_slider, original_image)
155
- aligned_slider.change(lambda i: aligned_frames[i] if 0 <= i < len(aligned_frames) else None, aligned_slider, aligned_image)
 
 
156
 
157
- reset_btn = gr.Button("🔄 Reset Tab")
158
- reset_btn.click(
159
  reset_intra_stack,
160
  outputs=[
161
  file_input, ref_slider, ext_ref_file, ext_ref_slider,
@@ -168,10 +187,21 @@ with gr.Blocks() as demo:
168
  ref_input = gr.File(label="Reference Stack")
169
  mov_input = gr.File(label="Moving Stack")
170
 
 
 
 
 
 
 
 
 
 
 
 
171
  with gr.Row():
172
  show_adv_ref = gr.Checkbox(label="Show Advanced Settings", value=False)
173
  mode_dropdown_ref = gr.Dropdown(["TRANSLATION", "RIGID_BODY", "SCALED_ROTATION", "AFFINE", "BILINEAR"],
174
- value="RIGID_BODY", label="Transformation Mode", visible=False)
175
 
176
  show_adv_ref.change(lambda v: gr.update(visible=v), show_adv_ref, mode_dropdown_ref)
177
  ref_btn = gr.Button("▶️ Register")
@@ -191,23 +221,30 @@ with gr.Blocks() as demo:
191
  ref_slider.change(lambda i: ref_frames[i] if 0 <= i < len(ref_frames) else None, ref_slider, ref_image)
192
  reg_slider.change(lambda i: reg_frames[i] if 0 <= i < len(reg_frames) else None, reg_slider, reg_image)
193
 
194
- reset_ref_btn = gr.Button("🔄 Reset Tab")
195
- reset_ref_btn.click(
196
  reset_reference_based,
197
  outputs=[ref_input, mov_input, ref_image, ref_slider, reg_image, reg_slider, download_ref]
198
  )
199
 
200
-
201
  with gr.Tab("🧩 Frame-to-Frame Alignment"):
202
  with gr.Row():
203
  frame_file = gr.File(label="Upload Stack")
204
  ref_idx = gr.Slider(label="Reference Frame", minimum=0, maximum=0, value=0, step=1)
205
  mov_idx = gr.Slider(label="Moving Frame", minimum=0, maximum=0, value=0, step=1)
206
 
 
 
 
 
 
 
 
 
 
207
  with gr.Row():
208
  show_adv_ftf = gr.Checkbox(label="Show Advanced Settings", value=False)
209
  mode_dropdown_ftf = gr.Dropdown(["TRANSLATION", "RIGID_BODY", "SCALED_ROTATION", "AFFINE", "BILINEAR"],
210
- value="RIGID_BODY", label="Transformation Mode", visible=False)
211
 
212
  show_adv_ftf.change(lambda v: gr.update(visible=v), show_adv_ftf, mode_dropdown_ftf)
213
  frame_btn = gr.Button("▶️ Register Frame")
@@ -215,16 +252,59 @@ with gr.Blocks() as demo:
215
  download_ftf = gr.File(label="Download")
216
 
217
  frame_file.change(
218
- lambda f: [gr.update(value=0, maximum=len(iio.mimread(f)) - 1)]*2 if f else [gr.update(value=0, maximum=0)]*2,
219
  frame_file, [ref_idx, mov_idx]
220
  )
221
- frame_btn.click(frame_to_frame_align, [frame_file, ref_idx, mov_idx, mode_dropdown_ftf], [frame_output, download_ftf])
222
 
223
- reset_ftf_btn = gr.Button("🔄 Reset Tab")
224
- reset_ftf_btn.click(
 
 
 
225
  reset_frame_to_frame,
226
  outputs=[frame_file, ref_idx, mov_idx, frame_output, download_ftf]
227
  )
228
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  if __name__ == "__main__":
230
  demo.launch()
 
5
  import imageio.v2 as iio
6
  import tifffile
7
  import tempfile
8
+ import urllib.request
9
 
10
  from core.utils import *
11
 
 
13
  original_frames, aligned_frames = [], []
14
  ref_frames, mov_frames, reg_frames = [], [], []
15
  custom_stack, reg_result = [], None
 
16
 
17
+ # Reset functions
18
  def reset_intra_stack():
19
  global original_frames, aligned_frames
20
  original_frames, aligned_frames = [], []
21
+ return [None, gr.update(value=0, minimum=0, maximum=0), None, gr.update(value=0, minimum=0, maximum=0),
22
+ None, gr.update(value=0, minimum=0, maximum=0), None, gr.update(value=0, minimum=0, maximum=0), None]
23
 
24
  def reset_reference_based():
25
  global ref_frames, mov_frames, reg_frames
26
  ref_frames, mov_frames, reg_frames = [], [], []
27
+ return [None, None, None, gr.update(value=0, minimum=0, maximum=0),
28
+ None, gr.update(value=0, minimum=0, maximum=0), None]
29
 
30
  def reset_frame_to_frame():
31
  global custom_stack, reg_result
32
  custom_stack, reg_result = [], None
33
+ return [None, gr.update(value=0, minimum=0, maximum=0),
34
+ gr.update(value=0, minimum=0, maximum=0), None, None]
35
 
36
+ # Registration logic
 
37
  def intra_stack_align(f, ref_idx, ext_file, ext_idx, mode):
38
  global original_frames, aligned_frames
39
  stack = load_stack(f)
40
  original_frames = [Image.fromarray(fr) for fr in stack]
41
  sr = StackReg(get_sr_mode(mode))
42
 
43
+ ref = load_stack(ext_file)[ext_idx] if ext_file else stack[ref_idx]
 
 
 
 
 
44
  aligned = [sr.register_transform(ref, fr) for fr in stack]
45
  aligned = normalize_stack(np.stack(aligned))
46
  aligned_frames = [upscale(Image.fromarray(fr)) for fr in aligned]
 
49
  tifffile.imwrite(path, aligned, photometric='minisblack')
50
 
51
  return (
52
+ original_frames[0], gr.update(value=0, maximum=len(original_frames)-1),
53
+ aligned_frames[0], gr.update(value=0, maximum=len(aligned_frames)-1), path
 
 
 
54
  )
55
 
56
  def reference_align(ref_file, mov_file, mode):
 
59
  mov_stack = load_stack(mov_file)
60
  ref_frames = [Image.fromarray(f) for f in ref_stack]
61
  mov_frames = [Image.fromarray(f) for f in mov_stack]
62
+
63
  sr = StackReg(get_sr_mode(mode))
64
  aligned = [sr.register_transform(ref_stack[0], f) for f in mov_stack]
65
  aligned = normalize_stack(np.stack(aligned))
66
  reg_frames = [upscale(Image.fromarray(f)) for f in aligned]
67
+
68
  path = tempfile.NamedTemporaryFile(suffix=".tif", delete=False).name
69
  tifffile.imwrite(path, aligned, photometric='minisblack')
70
  return ref_frames[0], gr.update(value=0, maximum=len(ref_frames)-1), \
 
74
  global custom_stack, reg_result
75
  stack = load_stack(file)
76
  custom_stack = [Image.fromarray(f) for f in stack]
77
+
78
  sr = StackReg(get_sr_mode(mode))
79
  aligned = sr.register_transform(stack[ref_idx], stack[mov_idx])
80
  aligned = normalize_stack(np.stack([aligned]))[0]
81
  reg_result = Image.fromarray(aligned)
82
+
83
  path = tempfile.NamedTemporaryFile(suffix=".tif", delete=False).name
84
  tifffile.imwrite(path, aligned[np.newaxis, ...], photometric='minisblack')
85
  return reg_result, path
86
 
87
+ # URL loading
88
+ def load_from_url(request: gr.Request):
89
+ params = request.query_params
90
+ if "file_url" in params:
91
+ try:
92
+ url = params["file_url"]
93
+ tmp_path = tempfile.mktemp(suffix=".tif")
94
+ urllib.request.urlretrieve(url, tmp_path)
95
+ return [gr.update(value=tmp_path)]
96
+ except Exception as e:
97
+ print(f"[URL load failed] {e}")
98
+ return [None]
99
 
100
  # Interface
101
  with gr.Blocks() as demo:
 
110
  file_input = gr.File(label="Upload Stack to Register")
111
  use_ext_ref = gr.Checkbox(label="Use external reference stack")
112
 
113
+ gr.Examples(
114
+ examples=[
115
+ ["https://github.com/glichtner/pystackreg/raw/master/examples/data/pc12-unreg.tif"]
116
+ ],
117
+ inputs=[file_input],
118
+ label="Try with Example TIFF"
119
+ )
120
+
121
  with gr.Row():
122
  ref_slider = gr.Slider(label="Reference Frame (from uploaded stack)", minimum=0, maximum=0, value=0, step=1, visible=True)
123
  ext_ref_file = gr.File(label="Upload External Reference Stack (.tif)", visible=False)
124
  ext_ref_slider = gr.Slider(label="Reference Frame (from external stack)", minimum=0, maximum=0, value=0, step=1, visible=False)
125
 
126
  use_ext_ref.change(
127
+ lambda v: (
128
+ gr.update(visible=not v),
129
+ gr.update(visible=v),
130
+ gr.update(visible=v)
131
  ),
132
  use_ext_ref,
133
  [ref_slider, ext_ref_file, ext_ref_slider]
 
140
  )
141
 
142
  with gr.Row():
143
+ show_adv = gr.Checkbox(label="Show Advanced Settings", value=False)
144
  mode_dropdown = gr.Dropdown(["TRANSLATION", "RIGID_BODY", "SCALED_ROTATION", "AFFINE", "BILINEAR"],
145
+ value="RIGID_BODY", visible=False, label="Transformation Mode")
146
 
147
+ show_adv.change(lambda v: gr.update(visible=v), show_adv, mode_dropdown)
148
  run_btn = gr.Button("▶️ Align Stack")
149
 
150
  with gr.Row():
 
169
  [original_image, original_slider, aligned_image, aligned_slider, download]
170
  )
171
 
172
+ original_slider.change(lambda i: original_frames[i] if 0 <= i < len(original_frames) else None,
173
+ original_slider, original_image)
174
+ aligned_slider.change(lambda i: aligned_frames[i] if 0 <= i < len(aligned_frames) else None,
175
+ aligned_slider, aligned_image)
176
 
177
+ gr.Button("🔄 Reset Tab").click(
 
178
  reset_intra_stack,
179
  outputs=[
180
  file_input, ref_slider, ext_ref_file, ext_ref_slider,
 
187
  ref_input = gr.File(label="Reference Stack")
188
  mov_input = gr.File(label="Moving Stack")
189
 
190
+ gr.Examples(
191
+ examples=[
192
+ [
193
+ "https://github.com/glichtner/pystackreg/raw/master/examples/data/pc12-unreg.tif",
194
+ "https://github.com/glichtner/pystackreg/raw/master/examples/data/pc12-reg-translation.tif"
195
+ ]
196
+ ],
197
+ inputs=[ref_input, mov_input],
198
+ label="Try with Example Stacks"
199
+ )
200
+
201
  with gr.Row():
202
  show_adv_ref = gr.Checkbox(label="Show Advanced Settings", value=False)
203
  mode_dropdown_ref = gr.Dropdown(["TRANSLATION", "RIGID_BODY", "SCALED_ROTATION", "AFFINE", "BILINEAR"],
204
+ value="RIGID_BODY", visible=False, label="Transformation Mode")
205
 
206
  show_adv_ref.change(lambda v: gr.update(visible=v), show_adv_ref, mode_dropdown_ref)
207
  ref_btn = gr.Button("▶️ Register")
 
221
  ref_slider.change(lambda i: ref_frames[i] if 0 <= i < len(ref_frames) else None, ref_slider, ref_image)
222
  reg_slider.change(lambda i: reg_frames[i] if 0 <= i < len(reg_frames) else None, reg_slider, reg_image)
223
 
224
+ gr.Button("🔄 Reset Tab").click(
 
225
  reset_reference_based,
226
  outputs=[ref_input, mov_input, ref_image, ref_slider, reg_image, reg_slider, download_ref]
227
  )
228
 
 
229
  with gr.Tab("🧩 Frame-to-Frame Alignment"):
230
  with gr.Row():
231
  frame_file = gr.File(label="Upload Stack")
232
  ref_idx = gr.Slider(label="Reference Frame", minimum=0, maximum=0, value=0, step=1)
233
  mov_idx = gr.Slider(label="Moving Frame", minimum=0, maximum=0, value=0, step=1)
234
 
235
+ gr.Examples(
236
+ examples=[
237
+ ["https://github.com/glichtner/pystackreg/raw/master/examples/data/pc12-unreg.tif"]
238
+ ],
239
+ inputs=[frame_file],
240
+ label="Try with Example Stack"
241
+ )
242
+
243
+
244
  with gr.Row():
245
  show_adv_ftf = gr.Checkbox(label="Show Advanced Settings", value=False)
246
  mode_dropdown_ftf = gr.Dropdown(["TRANSLATION", "RIGID_BODY", "SCALED_ROTATION", "AFFINE", "BILINEAR"],
247
+ value="RIGID_BODY", visible=False, label="Transformation Mode")
248
 
249
  show_adv_ftf.change(lambda v: gr.update(visible=v), show_adv_ftf, mode_dropdown_ftf)
250
  frame_btn = gr.Button("▶️ Register Frame")
 
252
  download_ftf = gr.File(label="Download")
253
 
254
  frame_file.change(
255
+ lambda f: [gr.update(value=0, maximum=len(iio.mimread(f)) - 1)] * 2 if f else [gr.update(value=0, maximum=0)] * 2,
256
  frame_file, [ref_idx, mov_idx]
257
  )
 
258
 
259
+ frame_btn.click(frame_to_frame_align,
260
+ [frame_file, ref_idx, mov_idx, mode_dropdown_ftf],
261
+ [frame_output, download_ftf])
262
+
263
+ gr.Button("🔄 Reset Tab").click(
264
  reset_frame_to_frame,
265
  outputs=[frame_file, ref_idx, mov_idx, frame_output, download_ftf]
266
  )
267
 
268
+ @demo.load(
269
+ outputs=[file_input, ref_slider, frame_file, ref_idx, mov_idx, ref_input, mov_input]
270
+ )
271
+ def load_from_query(request: gr.Request):
272
+ params = request.query_params
273
+ results = [None] * 7 # 7 outputs
274
+
275
+ # One-stack file case (for ref-based + frame-to-frame)
276
+ if "file_url" in params:
277
+ try:
278
+ url = params["file_url"]
279
+ tmp_path = tempfile.mktemp(suffix=".tif")
280
+ urllib.request.urlretrieve(url, tmp_path)
281
+ stack = iio.mimread(tmp_path)
282
+ max_frame = len(stack) - 1
283
+
284
+ results[0] = tmp_path # file_input
285
+ results[1] = gr.update(value=0, maximum=max_frame) # ref_slider
286
+ results[2] = tmp_path # frame_file
287
+ results[3] = gr.update(value=0, maximum=max_frame) # ref_idx
288
+ results[4] = gr.update(value=1 if max_frame >= 1 else 0, maximum=max_frame) # mov_idx
289
+
290
+ except Exception as e:
291
+ print(f"[Error loading file_url] {e}")
292
+
293
+ # Two-stack file case (for stack-based alignment)
294
+ if "file_url_1" in params and "file_url_2" in params:
295
+ try:
296
+ tmp_path_1 = tempfile.mktemp(suffix=".tif")
297
+ tmp_path_2 = tempfile.mktemp(suffix=".tif")
298
+ urllib.request.urlretrieve(params["file_url_1"], tmp_path_1)
299
+ urllib.request.urlretrieve(params["file_url_2"], tmp_path_2)
300
+ results[5] = tmp_path_1 # ref_input
301
+ results[6] = tmp_path_2 # mov_input
302
+ except Exception as e:
303
+ print(f"[Error loading file_url_1 or file_url_2] {e}")
304
+
305
+ return results
306
+
307
+
308
+
309
  if __name__ == "__main__":
310
  demo.launch()