numpy
matplotlib
import gradio as gr
import numpy as np
import matplotlib.pyplot as plt
def generate_synthetic_kidney(snr, enable_motion):
grid_size = 128
y, x = np.ogrid[:grid_size, :grid_size]
center_y, center_x = 64, 64
if enable_motion:
center_y += int(8 * np.sin(np.pi / 3))
dx = (x - center_x) / 35.0
dy = (y - center_y) / 45.0
r = np.sqrt(dx**2 + dy**2)
theta = np.arctan2(dy, dx)
bean_radius = (
1.0
+ 0.25 * np.cos(theta)
- 0.2 * np.sin(2 * theta)
)
kidney_mask = r <= bean_radius
img = np.zeros((grid_size, grid_size))
img[kidney_mask] = 1000.0
noise_sigma = 1000.0 / max(snr, 1)
noise_real = np.random.normal(
0, noise_sigma, (grid_size, grid_size)
)
noise_imag = np.random.normal(
0, noise_sigma, (grid_size, grid_size)
)
noisy_img = np.sqrt(
(img + noise_real)**2 + noise_imag**2
)
fig, ax = plt.subplots(figsize=(5, 5))
ax.imshow(noisy_img, cmap="gray")
ax.set_title(f"Synthetic Renal Scan (SNR: {snr} dB)")
ax.axis("off")
plt.tight_layout()
return fig
with gr.Blocks(title="Renal T1 Simulator") as demo:
gr.Markdown("# 🫘 Interactive Renal MRI Simulator")
gr.Markdown(
"Adjust parameters to generate a synthetic kidney slice "
"directly in your browser."
)
with gr.Column():
snr_slider = gr.Slider(
minimum=5,
maximum=50,
value=20,
step=1,
label="Signal-to-Noise Ratio (SNR)"
)
motion_checkbox = gr.Checkbox(
label="Simulate Respiratory Motion",
value=False
)
run_btn = gr.Button(
"Generate Phantom",
variant="primary"
)
plot_output = gr.Plot(
label="Reconstructed Slice"
)
run_btn.click(
fn=generate_synthetic_kidney,
inputs=[snr_slider, motion_checkbox],
outputs=[plot_output]
)
demo.launch()