drankush-ai commited on
Commit
16c13ca
·
verified ·
1 Parent(s): 4eb62c1

Upload folder using huggingface_hub

Browse files
Files changed (7) hide show
  1. README.md +6 -5
  2. app.py +357 -0
  3. heart_model.pkl +3 -0
  4. requirements.txt +161 -0
  5. runtime.txt +1 -0
  6. sample.nii.gz +3 -0
  7. vars.pkl +3 -0
README.md CHANGED
@@ -1,12 +1,13 @@
1
  ---
2
- title: LAViz
3
- emoji: 👀
4
- colorFrom: green
5
- colorTo: pink
6
  sdk: gradio
7
- sdk_version: 6.5.1
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Left Atrium Heart Segmentation
3
+ emoji: 🫀
4
+ colorFrom: indigo
5
+ colorTo: purple
6
  sdk: gradio
7
+ sdk_version: 4.37.2
8
  app_file: app.py
9
  pinned: false
10
+ license: apache-2.0
11
  ---
12
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,357 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import cv2
4
+ import numpy as np
5
+ from pathlib import Path
6
+ from huggingface_hub import snapshot_download
7
+ from fastMONAI.vision_all import *
8
+ from fastMONAI.vision_inference import load_system_resources, inference, compute_binary_tumor_volume
9
+ import sys
10
+ import os
11
+ import requests
12
+ from groq import Groq
13
+ from dotenv import load_dotenv
14
+ import math
15
+ import plotly.graph_objects as go
16
+ from skimage import measure
17
+
18
+ # Load environment variables (local .env or HuggingFace Secrets)
19
+ load_dotenv(dotenv_path=Path.cwd().parent / '.env')
20
+ GROQ_API_KEY = os.environ.get('GROQ_API_KEY')
21
+ groq_client = Groq(api_key=GROQ_API_KEY)
22
+
23
+
24
+ # Debug: List all symbols imported from fastMONAI.vision_all
25
+ print("[DEBUG] fastMONAI.vision_all symbols:", dir())
26
+ from git import Repo
27
+ import os
28
+
29
+ #Additional support for local execution:-
30
+ #import pathlib
31
+ #temp = pathlib.PosixPath
32
+ #pathlib.PosixPath = pathlib.WindowsPath
33
+ #pathlib.PosixPath = temp
34
+
35
+ # Local execution setup
36
+ clone_dir = Path.cwd()
37
+ # URI = os.getenv('PAT_Token_URI')
38
+
39
+ # if os.path.exists(clone_dir):
40
+ # pass
41
+ # else:
42
+ # Repo.clone_from(URI, clone_dir)
43
+
44
+ def extract_slices_from_mask(img, mask_data, view):
45
+ """Extract and resize slices from the 3D [W, H, D] image and mask data based on the selected view."""
46
+ slices = []
47
+ target_size = (320, 320)
48
+
49
+ for idx in range(img.shape[2] if view == "Sagittal" else img.shape[1] if view == "Axial" else img.shape[0]):
50
+ if view == "Sagittal":
51
+ slice_img, slice_mask = img[:, :, idx], mask_data[:, :, idx]
52
+ elif view == "Axial":
53
+ slice_img, slice_mask = img[:, idx, :], mask_data[:, idx, :]
54
+ elif view == "Coronal":
55
+ slice_img, slice_mask = img[idx, :, :], mask_data[idx, :, :]
56
+
57
+ slice_img = np.fliplr(np.rot90(slice_img, -1))
58
+ slice_mask = np.fliplr(np.rot90(slice_mask, -1))
59
+
60
+ slice_img_resized, slice_mask_resized = resize_and_pad(slice_img, slice_mask, target_size)
61
+ slices.append((slice_img_resized, slice_mask_resized))
62
+
63
+ return slices
64
+
65
+ def resize_and_pad(slice_img, slice_mask, target_size):
66
+ """Resize and pad the image and mask to fit the target size while maintaining the aspect ratio."""
67
+ h, w = slice_img.shape
68
+ scale = min(target_size[0] / w, target_size[1] / h)
69
+ new_w, new_h = int(w * scale), int(h * scale)
70
+
71
+ resized_img = cv2.resize(slice_img, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
72
+ resized_mask = cv2.resize(slice_mask, (new_w, new_h), interpolation=cv2.INTER_NEAREST)
73
+
74
+ pad_w = (target_size[0] - new_w) // 2
75
+ pad_h = (target_size[1] - new_h) // 2
76
+
77
+ padded_img = np.pad(resized_img, ((pad_h, target_size[1] - new_h - pad_h), (pad_w, target_size[0] - new_w - pad_w)), mode='constant', constant_values=0)
78
+ padded_mask = np.pad(resized_mask, ((pad_h, target_size[1] - new_h - pad_h), (pad_w, target_size[0] - new_w - pad_w)), mode='constant', constant_values=0)
79
+
80
+ return padded_img, padded_mask
81
+
82
+ def normalize_image(slice_img):
83
+ """Normalize the image to the range [0, 255] safely."""
84
+ slice_img_min, slice_img_max = slice_img.min(), slice_img.max()
85
+ if slice_img_min == slice_img_max: # Avoid division by zero
86
+ return np.zeros_like(slice_img, dtype=np.uint8)
87
+ normalized_img = (slice_img - slice_img_min) / (slice_img_max - slice_img_min) * 255
88
+ return normalized_img.astype(np.uint8)
89
+
90
+ def get_fused_image(img, pred_mask, view, alpha=0.8):
91
+ """Fuse a grayscale image with a mask overlay and flip both horizontally and vertically."""
92
+ gray_img_colored = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
93
+ mask_color = np.array([255, 0, 0])
94
+ colored_mask = (pred_mask[..., None] * mask_color).astype(np.uint8)
95
+
96
+ fused = cv2.addWeighted(gray_img_colored, alpha, colored_mask, 1 - alpha, 0)
97
+
98
+ # Flip the fused image vertically and horizontally
99
+ fused_flipped = cv2.flip(fused, -1) # Flip both vertically and horizontally
100
+
101
+ if view=='Sagittal':
102
+ return fused_flipped
103
+ elif view=='Coronal' or 'Axial':
104
+ rotated = cv2.flip(cv2.rotate(fused, cv2.ROTATE_90_COUNTERCLOCKWISE), 1)
105
+ return rotated
106
+
107
+ def get_bsa(height, weight):
108
+ """Calculate Body Surface Area using the Mosteller formula."""
109
+ return math.sqrt((height * weight) / 3600)
110
+
111
+ def create_3d_mesh_file(mask_data, spacing, save_dir):
112
+ """Create a 3D mesh file from the segmentation mask using marching cubes."""
113
+ import trimesh
114
+
115
+ try:
116
+ # Convert to numpy if tensor
117
+ if hasattr(mask_data, 'numpy'):
118
+ mask_np = mask_data.numpy().astype(np.float32)
119
+ else:
120
+ mask_np = np.array(mask_data).astype(np.float32)
121
+
122
+ # Squeeze to 3D if needed
123
+ if mask_np.ndim == 4:
124
+ mask_np = mask_np[0]
125
+
126
+ print(f"[DEBUG] Mask shape: {mask_np.shape}, spacing: {spacing}, sum: {np.sum(mask_np)}")
127
+
128
+ # Check if mask has valid data
129
+ if np.sum(mask_np) < 100:
130
+ print("[DEBUG] Mask has too few positive voxels")
131
+ return None
132
+
133
+ # Apply marching cubes to extract surface mesh
134
+ verts, faces, normals, values = measure.marching_cubes(
135
+ mask_np, level=0.5, spacing=spacing
136
+ )
137
+
138
+ print(f"[DEBUG] Marching cubes: {len(verts)} vertices, {len(faces)} faces")
139
+
140
+ # Create trimesh object
141
+ mesh = trimesh.Trimesh(vertices=verts, faces=faces, vertex_normals=normals)
142
+
143
+ # Apply a crimson color to the mesh
144
+ mesh.visual.vertex_colors = [220, 20, 60, 255] # Crimson RGBA
145
+
146
+ # Export to GLB format
147
+ mesh_path = save_dir / "la_mesh.glb"
148
+ mesh.export(str(mesh_path), file_type='glb')
149
+
150
+ print(f"[DEBUG] Mesh exported to: {mesh_path}")
151
+
152
+ return str(mesh_path)
153
+ except Exception as e:
154
+ print(f"[DEBUG] Error creating 3D mesh: {e}")
155
+ import traceback
156
+ traceback.print_exc()
157
+ return None
158
+
159
+
160
+ def fetch_miracle_ref(gender, bsa_indexed=False):
161
+ """Fetch reference values from MIRACLE-API."""
162
+ param = "MXLAVi" if bsa_indexed else "MXLAV"
163
+ url = f"https://ref.miracle-api.workers.dev/exec?domain=LA_VF&parameter={param}&gender={gender.lower()}&method=SM_AI"
164
+ try:
165
+ response = requests.get(url)
166
+ if response.status_code == 200:
167
+ return response.json().get('results', {})
168
+ except Exception as e:
169
+ print(f"Error fetching MIRACLE-API: {e}")
170
+ return {}
171
+
172
+ def get_interpretation(volume, height, weight, gender, voxel_info):
173
+ """Generate interpretation using Groq LLM."""
174
+ bsa = get_bsa(height, weight)
175
+ lavi = volume / bsa
176
+
177
+ ref_lav = fetch_miracle_ref(gender, bsa_indexed=False)
178
+ ref_lavi = fetch_miracle_ref(gender, bsa_indexed=True)
179
+
180
+ system_prompt = f"""
181
+ You are a medical imaging assistant. You will be provided with patient data and cardiac segmentation results (specifically Left Atrium Volume - LAV).
182
+ Your task is to interpret these results using reference data from MIRACLE-API.
183
+
184
+ Input Data:
185
+ - LAV: {volume} mL
186
+ - Height: {height} cm, Weight: {weight} kg, Gender: {gender}
187
+ - Calculated BSA: {bsa:.2f} m²
188
+ - Calculated LAVi: {lavi:.2f} mL/m²
189
+ - Voxel Info: {voxel_info}
190
+ - Reference LAV (MIRACLE-API): {ref_lav}
191
+ - Reference LAVi (MIRACLE-API): {ref_lavi}
192
+
193
+ Instructions:
194
+ 1. Acknowledge the calculation method using the voxel info.
195
+ 2. Compare the volume and LAVi against the reference mean and ranges (ll: lower limit, ul: upper limit).
196
+ 3. State if the volume is enlarged or normal based on the Z-score/percentile (if you can estimate) or simply by comparing against the upper limit (ul).
197
+ 4. Format the response strictly as requested by the user, starting with 'MIRACLE-API'.
198
+ """
199
+
200
+ try:
201
+ completion = groq_client.chat.completions.create(
202
+ model="openai/gpt-oss-120b",
203
+ messages=[
204
+ {"role": "system", "content": system_prompt},
205
+ {"role": "user", "content": "Interpret the results."}
206
+ ],
207
+ temperature=0.1
208
+ )
209
+ return completion.choices[0].message.content
210
+ except Exception as e:
211
+ return f"Error generating interpretation: {e}"
212
+
213
+ def gradio_image_segmentation(fileobj, learn, reorder, resample, save_dir, view):
214
+ """Predict function using the learner and other resources."""
215
+
216
+ if view == None:
217
+ view = 'Sagittal'
218
+
219
+ img_path = Path(fileobj.name)
220
+
221
+ save_fn = 'pred_' + img_path.stem
222
+ save_path = save_dir / save_fn
223
+ org_img, input_img, org_size = med_img_reader(img_path,
224
+ reorder=reorder,
225
+ resample=resample,
226
+ only_tensor=False)
227
+
228
+ mask_data = inference(learn, reorder=reorder, resample=resample,
229
+ org_img=org_img, input_img=input_img,
230
+ org_size=org_size).data
231
+
232
+ if "".join(org_img.orientation) == "LSA":
233
+ mask_data = mask_data.permute(0,1,3,2)
234
+ mask_data = torch.flip(mask_data[0], dims=[1])
235
+ mask_data = torch.Tensor(mask_data)[None]
236
+
237
+ img = org_img.data
238
+ org_img.set_data(mask_data)
239
+ org_img.save(save_path)
240
+
241
+ slices = extract_slices_from_mask(img[0], mask_data[0], view)
242
+ fused_images = [(get_fused_image(
243
+ normalize_image(slice_img), # Normalize safely
244
+ slice_mask, view))
245
+ for slice_img, slice_mask in slices]
246
+
247
+ volume = compute_binary_tumor_volume(org_img)
248
+
249
+ # Voxel info for the notes
250
+ dx, dy, dz = org_img.spacing
251
+ voxel_vol = dx * dy * dz / 1000
252
+ total_voxels = int(np.sum(mask_data.numpy()))
253
+ voxel_info = f"{total_voxels:,} voxels with each voxel volume of {voxel_vol:.4f} mL"
254
+
255
+ # Create 3D mesh file
256
+ mesh_path = create_3d_mesh_file(mask_data, spacing=(dx, dy, dz), save_dir=save_dir)
257
+
258
+ return fused_images, round(float(volume), 2), voxel_info, mesh_path
259
+
260
+ def wrapped_segmentation(fileobj, height, weight, gender, view, display_mode):
261
+ fused_images, volume, voxel_info, mesh_path = gradio_image_segmentation(fileobj, learn, reorder, resample, save_dir, view)
262
+ notes = get_interpretation(volume, height, weight, gender, voxel_info)
263
+ # Return Model3D with the selected display_mode
264
+ model3d = gr.Model3D(value=mesh_path, height=420, zoom_speed=0.5, pan_speed=0.5, display_mode=display_mode)
265
+ return fused_images, volume, notes, model3d
266
+
267
+ # Initialize the system
268
+ models_path = Path.cwd()
269
+ save_dir = Path.cwd() / 'hs_pred'
270
+ save_dir.mkdir(parents=True, exist_ok=True)
271
+
272
+
273
+ # Debug: Check if load_system_resources is defined
274
+ learn, reorder, resample = load_system_resources(models_path=models_path,
275
+ learner_fn='heart_model.pkl',
276
+ variables_fn='vars.pkl')
277
+
278
+ # Gradio interface setup with light theme
279
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
280
+ gr.Markdown("# LAViz - Left Atrium Visualization & Analysis")
281
+
282
+ with gr.Row():
283
+ # Left Column - Inputs
284
+ with gr.Column():
285
+ input_file = gr.File(label="Upload MRI (.nii, .nii.gz)", file_types=[".nii", ".nii.gz"])
286
+ view_selector = gr.Radio(
287
+ choices=["Axial", "Coronal", "Sagittal"],
288
+ value='Sagittal',
289
+ label="Select View (Sagittal by default)"
290
+ )
291
+ with gr.Row():
292
+ height_in = gr.Number(label="Height (cm)", value=None)
293
+ weight_in = gr.Number(label="Weight (kg)", value=None)
294
+ gender_in = gr.Radio(choices=["Male", "Female"], value=None, label="Gender")
295
+
296
+ # 3D Display Mode selector (before Submit)
297
+ display_mode_selector = gr.Radio(
298
+ choices=["solid", "point_cloud", "wireframe"],
299
+ value="solid",
300
+ label="3D Display Mode",
301
+ info="Select display mode before clicking Submit. To change mode, click Clear and re-submit."
302
+ )
303
+
304
+ with gr.Row():
305
+ clear_btn = gr.Button("Clear", variant="secondary")
306
+ submit_btn = gr.Button("Submit", variant="primary")
307
+
308
+ # 3D Visualization below buttons
309
+ mesh_out = gr.Model3D(label="3D Left Atrium Model", height=420, zoom_speed=0.5, pan_speed=0.5)
310
+
311
+ # Right Column - Outputs
312
+ with gr.Column():
313
+ gallery_out = gr.Gallery(
314
+ label="Click an Image, and use Arrow Keys to scroll slices",
315
+ columns=3,
316
+ height=450
317
+ )
318
+ vol_out = gr.Textbox(label="Volume of the Left Atrium (mL):")
319
+ notes_out = gr.Markdown(label="Notes")
320
+
321
+ # Example handling - clicking fills all fields
322
+ gr.Examples(
323
+ examples=[[str(Path.cwd() / "sample.nii.gz"), "Sagittal", 172, 80, "Male"]],
324
+ inputs=[input_file, view_selector, height_in, weight_in, gender_in],
325
+ label="Examples"
326
+ )
327
+
328
+ # Clear action - clears all inputs AND outputs
329
+ def clear_all():
330
+ return (
331
+ None, # input_file
332
+ "Sagittal", # view_selector (reset to default)
333
+ None, # height_in
334
+ None, # weight_in
335
+ None, # gender_in
336
+ "solid", # display_mode_selector (reset to default)
337
+ None, # gallery_out
338
+ "", # vol_out
339
+ "", # notes_out
340
+ None, # mesh_out
341
+ )
342
+
343
+ clear_btn.click(
344
+ fn=clear_all,
345
+ inputs=[],
346
+ outputs=[input_file, view_selector, height_in, weight_in, gender_in, display_mode_selector, gallery_out, vol_out, notes_out, mesh_out]
347
+ )
348
+
349
+ # Submit action
350
+ submit_btn.click(
351
+ fn=wrapped_segmentation,
352
+ inputs=[input_file, height_in, weight_in, gender_in, view_selector, display_mode_selector],
353
+ outputs=[gallery_out, vol_out, notes_out, mesh_out]
354
+ )
355
+
356
+ # Launch the Gradio interface
357
+ demo.launch()
heart_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8afefff7a465f013ca5978f03f6d0a0c4aa1dd2650dc0308962f1ad66cee4ae6
3
+ size 19363377
requirements.txt ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==23.2.1
2
+ altair==5.5.0
3
+ anyio==4.11.0
4
+ asttokens==3.0.0
5
+ authlib==1.6.4
6
+ beautifulsoup4==4.13.5
7
+ blis==1.2.1
8
+ brotli==1.1.0
9
+ catalogue==2.0.10
10
+ certifi==2025.8.3
11
+ cffi==2.0.0
12
+ charset-normalizer==3.4.3
13
+ click==8.0.4
14
+ click-option-group==0.5.7
15
+ cloudpathlib==0.22.0
16
+ cmake==4.1.0
17
+ confection==0.1.5
18
+ contourpy==1.3.2
19
+ cryptography==46.0.1
20
+ cycler==0.12.1
21
+ cymem==2.0.11
22
+ datasets
23
+ decorator==5.2.1
24
+ Deprecated==1.2.18
25
+ distro==1.9.0
26
+ exceptiongroup==1.3.0
27
+ executing==2.2.1
28
+ fastai==2.7.12
29
+ fastapi==0.112.4
30
+ fastcore==1.5.55
31
+ fastdownload==0.0.7
32
+ fastMONAI==0.4.0.2
33
+ fastprogress==1.0.3
34
+ ffmpy==0.6.1
35
+ filelock==3.19.1
36
+ fonttools==4.60.0
37
+ fsspec==2025.9.0
38
+ gdown==5.2.0
39
+ gitdb==4.0.12
40
+ GitPython==3.1.45
41
+ gradio==4.37.2
42
+ gradio_client==1.0.2
43
+ groovy==0.1.2
44
+ h11==0.16.0
45
+ hf-transfer>=0.1.4
46
+ hf_xet>=1.0.0,<2.0.0
47
+ httpcore==1.0.9
48
+ httpx==0.28.1
49
+ huggingface-hub>=0.19
50
+ humanize==4.13.0
51
+ idna==3.10
52
+ imagedata==2.1.3
53
+ imageio==2.37.0
54
+ importlib-metadata==6.11.0
55
+ importlib_resources==6.5.2
56
+ IPython==8.37.0
57
+ isodate==0.7.2
58
+ itsdangerous==2.2.0
59
+ itk-core==5.4.4.post1
60
+ itk-io==5.4.4.post1
61
+ jedi==0.19.2
62
+ Jinja2==3.1.6
63
+ joblib==1.5.2
64
+ jsonschema==4.25.1
65
+ jsonschema-specifications==2025.9.1
66
+ kiwisolver==1.4.9
67
+ langcodes==3.5.0
68
+ language-data==1.3.0
69
+ lit==18.1.8
70
+ markdown-it-py==4.0.0
71
+ MarkupSafe==2.1.5
72
+ marisa-trie==1.3.1
73
+ matplotlib==3.10.6
74
+ matplotlib-inline==0.1.7
75
+ mdurl==0.1.2
76
+ monai==1.2.0
77
+ mpmath==1.3.0
78
+ murmurhash==1.0.13
79
+ narwhals==2.5.0
80
+ networkx==3.4.2
81
+ nibabel==5.3.2
82
+ numpy==1.26.4
83
+ opencv-python==4.11.0.86
84
+ orjson==3.11.3
85
+ packaging==25.0
86
+ pandas==2.3.2
87
+ parso==0.8.5
88
+ pexpect==4.9.0
89
+ Pillow==10.4.0
90
+ preshed==3.0.10
91
+ progressbar2==4.5.0
92
+ prompt-toolkit==3.0.52
93
+ protobuf<4
94
+ psutil==5.9.8
95
+ ptyprocess==0.7.0
96
+ pure-eval==0.2.3
97
+ pycparser==2.23
98
+ pydantic==2.10.6
99
+ pydicom==2.4.4
100
+ pydub==0.25.1
101
+ Pygments==2.19.2
102
+ pynetdicom==1.5.7
103
+ pyparsing==3.2.5
104
+ PySocks==1.7.1
105
+ python-dateutil==2.8.2
106
+ python-magic==0.4.27
107
+ python-multipart==0.0.20
108
+ python-utils==3.9.1
109
+ pytz==2025.2
110
+ PyWavelets==1.8.0
111
+ PyYAML==6.0.3
112
+ referencing==0.36.2
113
+ requests==2.32.5
114
+ rich==14.1.0
115
+ rpds-py==0.27.1
116
+ ruff==0.13.2
117
+ safehttpx==0.1.6
118
+ scikit-build==0.18.1
119
+ scikit-image==0.19.3
120
+ scikit-learn==1.7.2
121
+ scipy==1.15.3
122
+ semantic-version==2.10.0
123
+ shellingham==1.5.4
124
+ SimpleITK==2.5.2
125
+ smart-open==7.3.1
126
+ smmap==5.0.2
127
+ sniffio==1.3.1
128
+ sortedcontainers==2.4.0
129
+ soupsieve==2.8
130
+ spacy==3.8.7
131
+ spacy-legacy==3.0.12
132
+ spacy-loggers==1.0.5
133
+ spaces==0.42.1
134
+ srsly==2.5.1
135
+ stack-data==0.6.3
136
+ starlette==0.38.6
137
+ sympy==1.14.0
138
+ thinc==8.3.4
139
+ threadpoolctl==3.6.0
140
+ tifffile==2025.5.10
141
+ tomli==2.2.1
142
+ tomlkit==0.12.0
143
+ torch==2.0.1
144
+ torchio==0.18.91
145
+ torchvision==0.15.2
146
+ tqdm==4.67.1
147
+ traitlets==5.14.3
148
+
149
+ typer==0.19.2
150
+ typing-extensions==4.15.0
151
+ tzdata==2025.2
152
+ urllib3==2.5.0
153
+ uvicorn==0.37.0
154
+ wasabi==1.1.3
155
+ wcwidth==0.2.14
156
+ weasel==0.4.1
157
+ websockets==11.0.3
158
+ wrapt==1.17.3
159
+ xlrd==2.0.2
160
+ xnat==0.7.2
161
+ zipp==3.23.0
runtime.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ python-3.11
sample.nii.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:05477be1b339567c8b304dafa737ad22be268024140197eeae9f14172a76e0c4
3
+ size 16059519
vars.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dd8458577a45f5ee60fc50a8ec5f6a499c6733b0f241a33cf76fa22bb9e715d3
3
+ size 173