Spaces:
Sleeping
Sleeping
Commit
Β·
b257e4f
1
Parent(s):
7f9c492
Add landmark tab
Browse files- app.py +218 -27
- requirements.txt +1 -1
app.py
CHANGED
|
@@ -6,8 +6,13 @@ import requests
|
|
| 6 |
import SimpleITK as sitk # noqa: N813
|
| 7 |
import spaces
|
| 8 |
import torch
|
| 9 |
-
from cinema import CineMA, ConvUNetR
|
| 10 |
from cinema.examples.cine_cmr import plot_cmr_views
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
from cinema.examples.inference.mae import plot_mae_reconstruction, reconstruct_images
|
| 12 |
from cinema.examples.inference.segmentation_lax_4c import (
|
| 13 |
plot_segmentations as plot_segmentations_lax,
|
|
@@ -63,7 +68,7 @@ def cmr_tab():
|
|
| 63 |
with gr.Blocks() as cmr_interface:
|
| 64 |
gr.Markdown(
|
| 65 |
"""
|
| 66 |
-
This page illustrates the spatial orientation of short-axis (SAX) and long-axis (LAX) views in 3D.
|
| 67 |
"""
|
| 68 |
)
|
| 69 |
with gr.Row():
|
|
@@ -222,7 +227,7 @@ def mae_tab():
|
|
| 222 |
with gr.Blocks() as mae_interface:
|
| 223 |
gr.Markdown(
|
| 224 |
"""
|
| 225 |
-
This page
|
| 226 |
"""
|
| 227 |
)
|
| 228 |
with gr.Row():
|
|
@@ -334,8 +339,7 @@ def segmentation_sax_tab():
|
|
| 334 |
with gr.Blocks() as sax_interface:
|
| 335 |
gr.Markdown(
|
| 336 |
"""
|
| 337 |
-
This page demonstrates the segmentation of cardiac structures in the
|
| 338 |
-
Please adjust the settings on the right panels and click the button to run the inference.
|
| 339 |
"""
|
| 340 |
)
|
| 341 |
|
|
@@ -345,17 +349,16 @@ def segmentation_sax_tab():
|
|
| 345 |
## Description
|
| 346 |
### Data
|
| 347 |
|
| 348 |
-
|
| 349 |
-
Image 101 - 150 are from the test set.
|
| 350 |
|
| 351 |
### Model
|
| 352 |
|
| 353 |
-
The available models are finetuned on different datasets ([ACDC](https://www.creatis.insa-lyon.fr/Challenge/acdc/), [M&Ms](https://www.ub.edu/mnms/), and [M&Ms2](https://www.ub.edu/mnms-2/)). For each dataset, there are
|
| 354 |
|
| 355 |
-
###
|
| 356 |
|
| 357 |
-
The left figure shows the segmentation of ventricles and myocardium every n time
|
| 358 |
-
The right figure
|
| 359 |
""")
|
| 360 |
with gr.Column(scale=3):
|
| 361 |
gr.Markdown("## Data Settings")
|
|
@@ -363,7 +366,7 @@ def segmentation_sax_tab():
|
|
| 363 |
minimum=101,
|
| 364 |
maximum=150,
|
| 365 |
step=1,
|
| 366 |
-
label="Choose an
|
| 367 |
value=101,
|
| 368 |
)
|
| 369 |
t_step = gr.Slider(
|
|
@@ -374,10 +377,10 @@ def segmentation_sax_tab():
|
|
| 374 |
value=2,
|
| 375 |
)
|
| 376 |
with gr.Column(scale=3):
|
| 377 |
-
gr.Markdown("## Model
|
| 378 |
trained_dataset = gr.Dropdown(
|
| 379 |
choices=["ACDC", "M&MS", "M&MS2"],
|
| 380 |
-
label="Choose which dataset the
|
| 381 |
value="ACDC",
|
| 382 |
)
|
| 383 |
seed = gr.Slider(
|
|
@@ -394,7 +397,7 @@ def segmentation_sax_tab():
|
|
| 394 |
gr.Markdown("## Ventricle and Myocardium Segmentation")
|
| 395 |
segmentation_plot = gr.Plot(show_label=False)
|
| 396 |
with gr.Column():
|
| 397 |
-
gr.Markdown("##
|
| 398 |
volume_plot = gr.Plot(show_label=False)
|
| 399 |
|
| 400 |
run_button.click(
|
|
@@ -476,8 +479,7 @@ def segmentation_lax_tab():
|
|
| 476 |
with gr.Blocks() as lax_interface:
|
| 477 |
gr.Markdown(
|
| 478 |
"""
|
| 479 |
-
This page demonstrates the segmentation of cardiac structures in the
|
| 480 |
-
Please adjust the settings on the right panels and click the button to run the inference.
|
| 481 |
"""
|
| 482 |
)
|
| 483 |
|
|
@@ -487,16 +489,16 @@ def segmentation_lax_tab():
|
|
| 487 |
## Description
|
| 488 |
### Data
|
| 489 |
|
| 490 |
-
There are four example
|
| 491 |
|
| 492 |
### Model
|
| 493 |
|
| 494 |
-
The available models are finetuned on [M&Ms2](https://www.ub.edu/mnms-2/).
|
| 495 |
|
| 496 |
-
###
|
| 497 |
|
| 498 |
The left figure shows the segmentation of ventricles and myocardium across all time frames.
|
| 499 |
-
The right figure
|
| 500 |
""")
|
| 501 |
with gr.Column(scale=3):
|
| 502 |
gr.Markdown("## Data Settings")
|
|
@@ -505,10 +507,10 @@ def segmentation_lax_tab():
|
|
| 505 |
maximum=4,
|
| 506 |
step=1,
|
| 507 |
label="Choose an image, ID is between 1 and 4",
|
| 508 |
-
value=
|
| 509 |
)
|
| 510 |
with gr.Column(scale=3):
|
| 511 |
-
gr.Markdown("## Model
|
| 512 |
seed = gr.Slider(
|
| 513 |
minimum=0,
|
| 514 |
maximum=2,
|
|
@@ -516,7 +518,7 @@ def segmentation_lax_tab():
|
|
| 516 |
label="Choose which seed the finetuning used",
|
| 517 |
value=0,
|
| 518 |
)
|
| 519 |
-
run_button = gr.Button("Run LAX segmentation inference", variant="primary")
|
| 520 |
|
| 521 |
with gr.Row():
|
| 522 |
with gr.Column():
|
|
@@ -534,6 +536,194 @@ def segmentation_lax_tab():
|
|
| 534 |
return lax_interface
|
| 535 |
|
| 536 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 537 |
with gr.Blocks(
|
| 538 |
theme=theme, title="CineMA: A Foundation Model for Cine Cardiac MRI"
|
| 539 |
) as demo:
|
|
@@ -542,7 +732,7 @@ with gr.Blocks(
|
|
| 542 |
# CineMA: A Foundation Model for Cine Cardiac MRI π₯π«
|
| 543 |
|
| 544 |
This demo showcases the capabilities of CineMA in multiple tasks.
|
| 545 |
-
For more details,
|
| 546 |
"""
|
| 547 |
)
|
| 548 |
|
|
@@ -553,7 +743,8 @@ with gr.Blocks(
|
|
| 553 |
mae_tab()
|
| 554 |
with gr.TabItem("Segmentation in SAX View"):
|
| 555 |
segmentation_sax_tab()
|
| 556 |
-
with gr.TabItem("Segmentation in LAX View"):
|
| 557 |
segmentation_lax_tab()
|
| 558 |
-
|
|
|
|
| 559 |
demo.launch()
|
|
|
|
| 6 |
import SimpleITK as sitk # noqa: N813
|
| 7 |
import spaces
|
| 8 |
import torch
|
| 9 |
+
from cinema import CineMA, ConvUNetR, ConvViT, heatmap_soft_argmax
|
| 10 |
from cinema.examples.cine_cmr import plot_cmr_views
|
| 11 |
+
from cinema.examples.inference.landmark_heatmap import (
|
| 12 |
+
plot_heatmaps,
|
| 13 |
+
plot_landmarks,
|
| 14 |
+
plot_lv,
|
| 15 |
+
)
|
| 16 |
from cinema.examples.inference.mae import plot_mae_reconstruction, reconstruct_images
|
| 17 |
from cinema.examples.inference.segmentation_lax_4c import (
|
| 18 |
plot_segmentations as plot_segmentations_lax,
|
|
|
|
| 68 |
with gr.Blocks() as cmr_interface:
|
| 69 |
gr.Markdown(
|
| 70 |
"""
|
| 71 |
+
This page illustrates the spatial orientation of short-axis (SAX) and long-axis (LAX) views in 3D.
|
| 72 |
"""
|
| 73 |
)
|
| 74 |
with gr.Row():
|
|
|
|
| 227 |
with gr.Blocks() as mae_interface:
|
| 228 |
gr.Markdown(
|
| 229 |
"""
|
| 230 |
+
This page demonstrates the masking and reconstruction process of the masked autoencoder. The model was trained with a mask ratio of 0.75 over 74,000 studies.
|
| 231 |
"""
|
| 232 |
)
|
| 233 |
with gr.Row():
|
|
|
|
| 339 |
with gr.Blocks() as sax_interface:
|
| 340 |
gr.Markdown(
|
| 341 |
"""
|
| 342 |
+
This page demonstrates the segmentation of cardiac structures in the short-axis (SAX) view.
|
|
|
|
| 343 |
"""
|
| 344 |
)
|
| 345 |
|
|
|
|
| 349 |
## Description
|
| 350 |
### Data
|
| 351 |
|
| 352 |
+
Images 101β150 are from the test set of [ACDC](https://www.creatis.insa-lyon.fr/Challenge/acdc/).
|
|
|
|
| 353 |
|
| 354 |
### Model
|
| 355 |
|
| 356 |
+
The available models are finetuned on different datasets ([ACDC](https://www.creatis.insa-lyon.fr/Challenge/acdc/), [M&Ms](https://www.ub.edu/mnms/), and [M&Ms2](https://www.ub.edu/mnms-2/)). For each dataset, there are three models finetuned with seeds: 0, 1, 2.
|
| 357 |
|
| 358 |
+
### Visualisation
|
| 359 |
|
| 360 |
+
The left figure shows the segmentation of ventricles and myocardium at every n time step across all SAX slices.
|
| 361 |
+
The right figure shows the volumes across all time frames and estimates the ejection fraction (EF) for the left ventricle (LV) and right ventricle (RV).
|
| 362 |
""")
|
| 363 |
with gr.Column(scale=3):
|
| 364 |
gr.Markdown("## Data Settings")
|
|
|
|
| 366 |
minimum=101,
|
| 367 |
maximum=150,
|
| 368 |
step=1,
|
| 369 |
+
label="Choose an image, ID is between 101 and 150",
|
| 370 |
value=101,
|
| 371 |
)
|
| 372 |
t_step = gr.Slider(
|
|
|
|
| 377 |
value=2,
|
| 378 |
)
|
| 379 |
with gr.Column(scale=3):
|
| 380 |
+
gr.Markdown("## Model Settings")
|
| 381 |
trained_dataset = gr.Dropdown(
|
| 382 |
choices=["ACDC", "M&MS", "M&MS2"],
|
| 383 |
+
label="Choose which dataset the model was finetuned on",
|
| 384 |
value="ACDC",
|
| 385 |
)
|
| 386 |
seed = gr.Slider(
|
|
|
|
| 397 |
gr.Markdown("## Ventricle and Myocardium Segmentation")
|
| 398 |
segmentation_plot = gr.Plot(show_label=False)
|
| 399 |
with gr.Column():
|
| 400 |
+
gr.Markdown("## Volume Estimation")
|
| 401 |
volume_plot = gr.Plot(show_label=False)
|
| 402 |
|
| 403 |
run_button.click(
|
|
|
|
| 479 |
with gr.Blocks() as lax_interface:
|
| 480 |
gr.Markdown(
|
| 481 |
"""
|
| 482 |
+
This page demonstrates the segmentation of cardiac structures in the long-axis (LAX) four-chamber (4C) view.
|
|
|
|
| 483 |
"""
|
| 484 |
)
|
| 485 |
|
|
|
|
| 489 |
## Description
|
| 490 |
### Data
|
| 491 |
|
| 492 |
+
There are four example images from the UK Biobank.
|
| 493 |
|
| 494 |
### Model
|
| 495 |
|
| 496 |
+
The available models are finetuned on [M&Ms2](https://www.ub.edu/mnms-2/). There are three models finetuned with seeds: 0, 1, 2.
|
| 497 |
|
| 498 |
+
### Visualisation
|
| 499 |
|
| 500 |
The left figure shows the segmentation of ventricles and myocardium across all time frames.
|
| 501 |
+
The right figure shows the volumes across all time frames and estimates the ejection fraction (EF).
|
| 502 |
""")
|
| 503 |
with gr.Column(scale=3):
|
| 504 |
gr.Markdown("## Data Settings")
|
|
|
|
| 507 |
maximum=4,
|
| 508 |
step=1,
|
| 509 |
label="Choose an image, ID is between 1 and 4",
|
| 510 |
+
value=1,
|
| 511 |
)
|
| 512 |
with gr.Column(scale=3):
|
| 513 |
+
gr.Markdown("## Model Settings")
|
| 514 |
seed = gr.Slider(
|
| 515 |
minimum=0,
|
| 516 |
maximum=2,
|
|
|
|
| 518 |
label="Choose which seed the finetuning used",
|
| 519 |
value=0,
|
| 520 |
)
|
| 521 |
+
run_button = gr.Button("Run LAX 4C segmentation inference", variant="primary")
|
| 522 |
|
| 523 |
with gr.Row():
|
| 524 |
with gr.Column():
|
|
|
|
| 536 |
return lax_interface
|
| 537 |
|
| 538 |
|
| 539 |
+
@spaces.GPU
|
| 540 |
+
def landmark_heatmap_inference(
|
| 541 |
+
images: torch.Tensor,
|
| 542 |
+
view: str,
|
| 543 |
+
transform: Compose,
|
| 544 |
+
model: ConvUNetR,
|
| 545 |
+
progress=gr.Progress(),
|
| 546 |
+
) -> tuple[np.ndarray, np.ndarray]:
|
| 547 |
+
model.to(device)
|
| 548 |
+
|
| 549 |
+
n_frames = images.shape[-1]
|
| 550 |
+
probs_list = []
|
| 551 |
+
coords_list = []
|
| 552 |
+
for t in tqdm(range(n_frames), total=n_frames):
|
| 553 |
+
progress((t + 1) / n_frames, desc=f"Processing frame {t + 1} / {n_frames}...")
|
| 554 |
+
batch = transform({view: torch.from_numpy(images[None, ..., 0, t])})
|
| 555 |
+
batch = {
|
| 556 |
+
k: v[None, ...].to(device=device, dtype=dtype) for k, v in batch.items()
|
| 557 |
+
}
|
| 558 |
+
with (
|
| 559 |
+
torch.no_grad(),
|
| 560 |
+
torch.autocast("cuda", dtype=dtype, enabled=torch.cuda.is_available()),
|
| 561 |
+
):
|
| 562 |
+
logits = model(batch)[view] # (1, 3, x, y)
|
| 563 |
+
probs = torch.sigmoid(logits) # (1, 3, width, height)
|
| 564 |
+
probs_list.append(probs[0].detach().to(torch.float32).cpu().numpy())
|
| 565 |
+
coords = heatmap_soft_argmax(probs)[0].detach().to(torch.float32).cpu().numpy()
|
| 566 |
+
coords = [int(x) for x in coords]
|
| 567 |
+
coords_list.append(coords)
|
| 568 |
+
probs = np.stack(probs_list, axis=-1) # (3, x, y, t)
|
| 569 |
+
coords = np.stack(coords_list, axis=-1) # (6, t)
|
| 570 |
+
return probs, coords
|
| 571 |
+
|
| 572 |
+
|
| 573 |
+
@spaces.GPU
|
| 574 |
+
def landmark_coordinate_inference(
|
| 575 |
+
images: torch.Tensor,
|
| 576 |
+
view: str,
|
| 577 |
+
transform: Compose,
|
| 578 |
+
model: ConvViT,
|
| 579 |
+
progress=gr.Progress(),
|
| 580 |
+
) -> np.ndarray:
|
| 581 |
+
model.to(device)
|
| 582 |
+
|
| 583 |
+
w, h, _, n_frames = images.shape
|
| 584 |
+
coords_list = []
|
| 585 |
+
for t in tqdm(range(n_frames), total=n_frames):
|
| 586 |
+
progress((t + 1) / n_frames, desc=f"Processing frame {t + 1} / {n_frames}...")
|
| 587 |
+
batch = transform({view: torch.from_numpy(images[None, ..., 0, t])})
|
| 588 |
+
batch = {
|
| 589 |
+
k: v[None, ...].to(device=device, dtype=dtype) for k, v in batch.items()
|
| 590 |
+
}
|
| 591 |
+
with (
|
| 592 |
+
torch.no_grad(),
|
| 593 |
+
torch.autocast("cuda", dtype=dtype, enabled=torch.cuda.is_available()),
|
| 594 |
+
):
|
| 595 |
+
coords = model(batch)[0].detach().to(torch.float32).cpu().numpy() # (6,)
|
| 596 |
+
coords *= np.array([w, h, w, h, w, h])
|
| 597 |
+
coords = [int(x) for x in coords]
|
| 598 |
+
coords_list.append(coords)
|
| 599 |
+
coords = np.stack(coords_list, axis=-1) # (6, t)
|
| 600 |
+
return coords
|
| 601 |
+
|
| 602 |
+
|
| 603 |
+
def landmark(image_id, view, method, seed, progress=gr.Progress()):
|
| 604 |
+
view = "lax_2c" if view == "LAX 2C" else "lax_4c"
|
| 605 |
+
method = method.lower()
|
| 606 |
+
|
| 607 |
+
# Download and load model
|
| 608 |
+
progress(0, desc="Downloading model...")
|
| 609 |
+
if method == "heatmap":
|
| 610 |
+
model = ConvUNetR.from_finetuned(
|
| 611 |
+
repo_id="mathpluscode/CineMA",
|
| 612 |
+
model_filename=f"finetuned/landmark_{method}/{view}/{view}_{seed}.safetensors",
|
| 613 |
+
config_filename=f"finetuned/landmark_{method}/{view}/config.yaml",
|
| 614 |
+
cache_dir=cache_dir,
|
| 615 |
+
)
|
| 616 |
+
elif method == "coordinate":
|
| 617 |
+
model = ConvViT.from_finetuned(
|
| 618 |
+
repo_id="mathpluscode/CineMA",
|
| 619 |
+
model_filename=f"finetuned/landmark_{method}/{view}/{view}_{seed}.safetensors",
|
| 620 |
+
config_filename=f"finetuned/landmark_{method}/{view}/config.yaml",
|
| 621 |
+
cache_dir=cache_dir,
|
| 622 |
+
)
|
| 623 |
+
else:
|
| 624 |
+
raise ValueError(f"Invalid method: {method}")
|
| 625 |
+
model.eval()
|
| 626 |
+
|
| 627 |
+
# Inference
|
| 628 |
+
progress(0, desc="Downloading data...")
|
| 629 |
+
transform = ScaleIntensityd(keys=view)
|
| 630 |
+
images = np.transpose(
|
| 631 |
+
sitk.GetArrayFromImage(
|
| 632 |
+
load_nifti_from_github(f"ukb/{image_id}/{image_id}_{view}.nii.gz")
|
| 633 |
+
)
|
| 634 |
+
)
|
| 635 |
+
|
| 636 |
+
if method == "heatmap":
|
| 637 |
+
_, coords = landmark_heatmap_inference(images, view, transform, model, progress)
|
| 638 |
+
elif method == "coordinate":
|
| 639 |
+
coords = landmark_coordinate_inference(images, view, transform, model, progress)
|
| 640 |
+
else:
|
| 641 |
+
raise ValueError(f"Invalid method: {method}")
|
| 642 |
+
|
| 643 |
+
landmark_fig = plot_landmarks(images, coords)
|
| 644 |
+
lv_fig = plot_lv(coords)
|
| 645 |
+
return landmark_fig, lv_fig
|
| 646 |
+
|
| 647 |
+
|
| 648 |
+
def landmark_tab():
|
| 649 |
+
with gr.Blocks() as landmark_interface:
|
| 650 |
+
gr.Markdown(
|
| 651 |
+
"""
|
| 652 |
+
This page demonstrates landmark localisation in the long-axis (LAX) two-chamber (2C) and four-chamber (4C) views
|
| 653 |
+
"""
|
| 654 |
+
)
|
| 655 |
+
|
| 656 |
+
with gr.Row():
|
| 657 |
+
with gr.Column(scale=4):
|
| 658 |
+
gr.Markdown("""
|
| 659 |
+
## Description
|
| 660 |
+
### Data
|
| 661 |
+
|
| 662 |
+
There are four example images from the UK Biobank.
|
| 663 |
+
|
| 664 |
+
### Model
|
| 665 |
+
|
| 666 |
+
The available models are finetuned on data from [Xue et al.](https://pubs.rsna.org/doi/10.1148/ryai.2021200197).
|
| 667 |
+
There are two types of landmark localisation models:
|
| 668 |
+
|
| 669 |
+
- **Heatmap**: predicts dense probability maps of landmarks
|
| 670 |
+
- **Coordinate**: predicts landmark coordinates directly
|
| 671 |
+
|
| 672 |
+
For each type, there are three models finetuned with seeds: 0, 1, 2.
|
| 673 |
+
|
| 674 |
+
### Visualisation
|
| 675 |
+
|
| 676 |
+
The left figure shows the landmark positions across all time frames.
|
| 677 |
+
The right figure shows the length of the left ventricle across all time frames and the estimates of two metrics:
|
| 678 |
+
- Mitral annular plane systolic excursion (MAPSE)
|
| 679 |
+
- Global longitudinal shortening (GLS)
|
| 680 |
+
""")
|
| 681 |
+
with gr.Column(scale=3):
|
| 682 |
+
gr.Markdown("## Data Settings")
|
| 683 |
+
image_id = gr.Slider(
|
| 684 |
+
minimum=1,
|
| 685 |
+
maximum=4,
|
| 686 |
+
step=1,
|
| 687 |
+
label="Choose an image, ID is between 1 and 4",
|
| 688 |
+
value=1,
|
| 689 |
+
)
|
| 690 |
+
view = gr.Dropdown(
|
| 691 |
+
choices=["LAX 2C", "LAX 4C"],
|
| 692 |
+
label="Choose which view to localise the landmarks",
|
| 693 |
+
value="LAX 2C",
|
| 694 |
+
)
|
| 695 |
+
with gr.Column(scale=3):
|
| 696 |
+
gr.Markdown("## Model Settings")
|
| 697 |
+
method = gr.Dropdown(
|
| 698 |
+
choices=["Heatmap", "Coordinate"],
|
| 699 |
+
label="Choose which method to use",
|
| 700 |
+
value="Heatmap",
|
| 701 |
+
)
|
| 702 |
+
seed = gr.Slider(
|
| 703 |
+
minimum=0,
|
| 704 |
+
maximum=2,
|
| 705 |
+
step=1,
|
| 706 |
+
label="Choose which seed the finetuning used",
|
| 707 |
+
value=0,
|
| 708 |
+
)
|
| 709 |
+
run_button = gr.Button("Run landmark localisation inference", variant="primary")
|
| 710 |
+
|
| 711 |
+
with gr.Row():
|
| 712 |
+
with gr.Column():
|
| 713 |
+
gr.Markdown("## Landmark Localisation")
|
| 714 |
+
landmark_plot = gr.Plot(show_label=False)
|
| 715 |
+
with gr.Column():
|
| 716 |
+
gr.Markdown("## Left Ventricle Length Estimation")
|
| 717 |
+
lv_plot = gr.Plot(show_label=False)
|
| 718 |
+
|
| 719 |
+
run_button.click(
|
| 720 |
+
fn=landmark,
|
| 721 |
+
inputs=[image_id, view, method, seed],
|
| 722 |
+
outputs=[landmark_plot, lv_plot],
|
| 723 |
+
)
|
| 724 |
+
return landmark_interface
|
| 725 |
+
|
| 726 |
+
|
| 727 |
with gr.Blocks(
|
| 728 |
theme=theme, title="CineMA: A Foundation Model for Cine Cardiac MRI"
|
| 729 |
) as demo:
|
|
|
|
| 732 |
# CineMA: A Foundation Model for Cine Cardiac MRI π₯π«
|
| 733 |
|
| 734 |
This demo showcases the capabilities of CineMA in multiple tasks.
|
| 735 |
+
For more details, check out our [GitHub](https://github.com/mathpluscode/CineMA).
|
| 736 |
"""
|
| 737 |
)
|
| 738 |
|
|
|
|
| 743 |
mae_tab()
|
| 744 |
with gr.TabItem("Segmentation in SAX View"):
|
| 745 |
segmentation_sax_tab()
|
| 746 |
+
with gr.TabItem("Segmentation in LAX 4C View"):
|
| 747 |
segmentation_lax_tab()
|
| 748 |
+
with gr.TabItem("Landmark Localisation in LAX 2C/4C View"):
|
| 749 |
+
landmark_tab()
|
| 750 |
demo.launch()
|
requirements.txt
CHANGED
|
@@ -17,6 +17,6 @@ scikit-learn==1.6.1
|
|
| 17 |
scipy==1.15.2
|
| 18 |
spaces==0.36.0
|
| 19 |
timm==1.0.15
|
| 20 |
-
git+https://github.com/mathpluscode/CineMA@
|
| 21 |
--extra-index-url https://download.pytorch.org/whl/cu113
|
| 22 |
torch==2.5.1
|
|
|
|
| 17 |
scipy==1.15.2
|
| 18 |
spaces==0.36.0
|
| 19 |
timm==1.0.15
|
| 20 |
+
git+https://github.com/mathpluscode/CineMA@edc0774baed3c2429a2a4ffaa36a3910f2780b2b#egg=cinema
|
| 21 |
--extra-index-url https://download.pytorch.org/whl/cu113
|
| 22 |
torch==2.5.1
|