Spaces:
Sleeping
Sleeping
Anirudh Balaraman commited on
Commit ·
e6301f6
1
Parent(s): 8d661c2
update app.py
Browse files- app.py +3 -116
- run_inference.py +1 -1
app.py
CHANGED
|
@@ -128,10 +128,11 @@ def display_slicer(
|
|
| 128 |
h_slice = h_data[:, :, slice_idx].astype(float)
|
| 129 |
|
| 130 |
# Normalize the heatmap slice to 0-1 if it isn't already
|
|
|
|
| 131 |
max_val = np.max(h_slice)
|
| 132 |
if max_val > 0:
|
| 133 |
h_slice = h_slice / max_val
|
| 134 |
-
|
| 135 |
# Mask out values below the user-defined threshold
|
| 136 |
h_overlay = np.ma.masked_where(h_slice < hm_thresh, h_slice)
|
| 137 |
|
|
@@ -156,120 +157,6 @@ def display_slicer(
|
|
| 156 |
st.pyplot(fig, use_container_width=False)
|
| 157 |
|
| 158 |
|
| 159 |
-
'''
|
| 160 |
-
def display_slicer(scan_paths, mask_path=None, bboxes=None, title="Scan Viewer", key_suffix=""):
|
| 161 |
-
"""
|
| 162 |
-
Displays slicer with Multi-Background Support, Mask Overlay, and Bounding Box Multiselect.
|
| 163 |
-
|
| 164 |
-
Args:
|
| 165 |
-
scan_paths: Dict of {Label: FilePath}. Example: {"T2W": "path/to/t2.nrrd", "ADC": "..."}
|
| 166 |
-
"""
|
| 167 |
-
# 1. Layout: Image/Slider (Left) | Controls (Right)
|
| 168 |
-
c_viewer, c_controls = st.columns([3, 1.5])
|
| 169 |
-
|
| 170 |
-
# --- CONTROLS SECTION (Right Column) ---
|
| 171 |
-
with c_controls:
|
| 172 |
-
st.write(f"**{title} Controls**")
|
| 173 |
-
|
| 174 |
-
# A. Background Selection
|
| 175 |
-
# We assume the first key in the dict is the default
|
| 176 |
-
available_scans = list(scan_paths.keys())
|
| 177 |
-
selected_scan_name = st.radio(
|
| 178 |
-
"Background Image", available_scans, index=0, key=f"bg_{key_suffix}"
|
| 179 |
-
)
|
| 180 |
-
current_file_path = scan_paths[selected_scan_name]
|
| 181 |
-
|
| 182 |
-
# B. Lesion Selection (Multiselect)
|
| 183 |
-
box_labels = []
|
| 184 |
-
selected_labels = []
|
| 185 |
-
if bboxes:
|
| 186 |
-
box_labels = [f"Lesion {i + 1}" for i in range(len(bboxes))]
|
| 187 |
-
st.write("---") # Divider
|
| 188 |
-
selected_labels = st.multiselect(
|
| 189 |
-
"Select Lesions", options=box_labels, default=box_labels, key=f"multi_{key_suffix}"
|
| 190 |
-
)
|
| 191 |
-
|
| 192 |
-
# C. Toggles
|
| 193 |
-
st.write("---")
|
| 194 |
-
show_mask = False
|
| 195 |
-
if mask_path and os.path.exists(mask_path):
|
| 196 |
-
show_mask = st.checkbox("Show Mask Overlay", value=False, key=f"mk_{key_suffix}")
|
| 197 |
-
|
| 198 |
-
# --- VIEWER SECTION (Left Column) ---
|
| 199 |
-
with c_viewer:
|
| 200 |
-
if not os.path.exists(current_file_path):
|
| 201 |
-
st.error(f"File not found: {current_file_path}")
|
| 202 |
-
return
|
| 203 |
-
|
| 204 |
-
# Load the selected background image
|
| 205 |
-
data, _ = load_nrrd(current_file_path)
|
| 206 |
-
|
| 207 |
-
if len(data.shape) != 3:
|
| 208 |
-
st.warning("Data is not 3D.")
|
| 209 |
-
return
|
| 210 |
-
|
| 211 |
-
total_slices = data.shape[2]
|
| 212 |
-
|
| 213 |
-
# D. Slider Logic
|
| 214 |
-
start_slice = total_slices // 2
|
| 215 |
-
# Auto-jump logic: If exactly one lesion is selected, jump to it
|
| 216 |
-
if len(selected_labels) == 1 and bboxes:
|
| 217 |
-
idx = int(selected_labels[0].split(" ")[1]) - 1
|
| 218 |
-
if 0 <= idx < len(bboxes):
|
| 219 |
-
b = bboxes[idx]
|
| 220 |
-
start_slice = int(b[2] + (b[5] // 2))
|
| 221 |
-
start_slice = max(0, min(start_slice, total_slices - 1))
|
| 222 |
-
|
| 223 |
-
slice_idx = st.slider(
|
| 224 |
-
"Select Slice (Z-Axis)", 0, total_slices - 1, start_slice, key=f"sl_{key_suffix}"
|
| 225 |
-
)
|
| 226 |
-
|
| 227 |
-
# E. Plotting
|
| 228 |
-
img_slice = data[:, :, slice_idx]
|
| 229 |
-
|
| 230 |
-
# Normalize Image (0-1)
|
| 231 |
-
img_slice = img_slice.astype(float)
|
| 232 |
-
|
| 233 |
-
fig, ax = plt.subplots(figsize=(5, 5))
|
| 234 |
-
ax.imshow(img_slice, cmap="gray", origin="upper")
|
| 235 |
-
|
| 236 |
-
# 1. Overlay Mask
|
| 237 |
-
if show_mask:
|
| 238 |
-
# Load mask on the fly (or cache it if slow)
|
| 239 |
-
|
| 240 |
-
m_data, _ = load_nrrd(mask_path)
|
| 241 |
-
# Check shape compatibility
|
| 242 |
-
if m_data.shape == data.shape:
|
| 243 |
-
mslice = m_data[:, :, slice_idx]
|
| 244 |
-
overlay = np.ma.masked_where(mslice == 0, mslice)
|
| 245 |
-
ax.imshow(overlay, cmap="Reds", alpha=0.5, origin="upper")
|
| 246 |
-
else:
|
| 247 |
-
# Fallback warning if mask dims don't match selected background
|
| 248 |
-
# (Common if ADC resolution != T2 resolution)
|
| 249 |
-
ax.text(5, 5, "Mask shape mismatch", color="red", fontsize=8)
|
| 250 |
-
|
| 251 |
-
# 2. Overlay Bounding Boxes
|
| 252 |
-
if bboxes:
|
| 253 |
-
for i, box in enumerate(bboxes):
|
| 254 |
-
label = f"Lesion {i + 1}"
|
| 255 |
-
if label not in selected_labels:
|
| 256 |
-
continue
|
| 257 |
-
|
| 258 |
-
bx, by, bz, bw, bh, bd = box
|
| 259 |
-
|
| 260 |
-
# Visibility check
|
| 261 |
-
if bz <= slice_idx < (bz + bd):
|
| 262 |
-
rect = patches.Rectangle(
|
| 263 |
-
(bx, by), bw, bh, linewidth=2, edgecolor="yellow", facecolor="none"
|
| 264 |
-
)
|
| 265 |
-
ax.add_patch(rect)
|
| 266 |
-
ax.text(bx, by - 5, f"L{i + 1}", color="yellow", fontsize=9, fontweight="bold")
|
| 267 |
-
|
| 268 |
-
ax.axis("off")
|
| 269 |
-
st.pyplot(fig, use_container_width=False)
|
| 270 |
-
|
| 271 |
-
'''
|
| 272 |
-
|
| 273 |
|
| 274 |
@st.cache_resource
|
| 275 |
def download_all_models():
|
|
@@ -551,7 +438,7 @@ if st.session_state.inference_done:
|
|
| 551 |
st.session_state.pirads = first_case.get("Predicted PIRAD Score")
|
| 552 |
st.session_state.risk = first_case.get("csPCa risk")
|
| 553 |
st.session_state.coords = first_case.get(
|
| 554 |
-
"Top left
|
| 555 |
)
|
| 556 |
|
| 557 |
else:
|
|
|
|
| 128 |
h_slice = h_data[:, :, slice_idx].astype(float)
|
| 129 |
|
| 130 |
# Normalize the heatmap slice to 0-1 if it isn't already
|
| 131 |
+
'''
|
| 132 |
max_val = np.max(h_slice)
|
| 133 |
if max_val > 0:
|
| 134 |
h_slice = h_slice / max_val
|
| 135 |
+
'''
|
| 136 |
# Mask out values below the user-defined threshold
|
| 137 |
h_overlay = np.ma.masked_where(h_slice < hm_thresh, h_slice)
|
| 138 |
|
|
|
|
| 157 |
st.pyplot(fig, use_container_width=False)
|
| 158 |
|
| 159 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
@st.cache_resource
|
| 162 |
def download_all_models():
|
|
|
|
| 438 |
st.session_state.pirads = first_case.get("Predicted PIRAD Score")
|
| 439 |
st.session_state.risk = first_case.get("csPCa risk")
|
| 440 |
st.session_state.coords = first_case.get(
|
| 441 |
+
"Top left coordinates of the patches(x,y,z)"
|
| 442 |
)
|
| 443 |
|
| 444 |
else:
|
run_inference.py
CHANGED
|
@@ -112,7 +112,7 @@ if __name__ == "__main__":
|
|
| 112 |
|
| 113 |
scaler = StandardScaler()
|
| 114 |
with open(
|
| 115 |
-
os.path.join(args.project_dir, "dataset", "cspca_train_tcia.json
|
| 116 |
) as f:
|
| 117 |
dataset_json = json.load(f)
|
| 118 |
train_clinical = [i["psa"] for i in dataset_json["train"]]
|
|
|
|
| 112 |
|
| 113 |
scaler = StandardScaler()
|
| 114 |
with open(
|
| 115 |
+
os.path.join(args.project_dir, "dataset", "cspca_train_tcia.json")
|
| 116 |
) as f:
|
| 117 |
dataset_json = json.load(f)
|
| 118 |
train_clinical = [i["psa"] for i in dataset_json["train"]]
|