Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -131,11 +131,6 @@ def drawOnTop(img, landmarks, original_shape):
|
|
| 131 |
# Draw measurement lines that follow the image tilt for visual accuracy
|
| 132 |
# Use corrected coordinates for accurate measurement, but draw tilted lines for visual appeal
|
| 133 |
|
| 134 |
-
# Calculate thoracic midline for bilateral measurements
|
| 135 |
-
thorax_xmin_corrected = min(np.min(RL_corrected[:, 0]), np.min(LL_corrected[:, 0]))
|
| 136 |
-
thorax_xmax_corrected = max(np.max(RL_corrected[:, 0]), np.max(LL_corrected[:, 0]))
|
| 137 |
-
thorax_midline_corrected = (thorax_xmin_corrected + thorax_xmax_corrected) / 2
|
| 138 |
-
|
| 139 |
# Heart (red line) - calculate positions from corrected coordinates
|
| 140 |
heart_xmin_corrected = np.min(H_corrected[:, 0])
|
| 141 |
heart_xmax_corrected = np.max(H_corrected[:, 0])
|
|
@@ -171,6 +166,9 @@ def drawOnTop(img, landmarks, original_shape):
|
|
| 171 |
(1, 0, 0), 2)
|
| 172 |
|
| 173 |
# Thorax (blue line) - calculate positions from corrected coordinates
|
|
|
|
|
|
|
|
|
|
| 174 |
# Find y at leftmost and rightmost points (corrected)
|
| 175 |
if np.min(RL_corrected[:, 0]) < np.min(LL_corrected[:, 0]):
|
| 176 |
thorax_ymin_corrected = RL_corrected[np.argmin(RL_corrected[:, 0]), 1]
|
|
@@ -209,54 +207,6 @@ def drawOnTop(img, landmarks, original_shape):
|
|
| 209 |
(int(thorax_end[0] - perp_x), int(thorax_end[1] - perp_y)),
|
| 210 |
(0, 0, 1), 2)
|
| 211 |
|
| 212 |
-
# === DRAW BILATERAL MEASUREMENT LINES ===
|
| 213 |
-
# Draw thoracic midline (vertical white dashed line)
|
| 214 |
-
midline_points_corrected = np.array([[thorax_midline_corrected, thorax_y_corrected - 100],
|
| 215 |
-
[thorax_midline_corrected, thorax_y_corrected + 100]])
|
| 216 |
-
midline_points_display = rotate_points(midline_points_corrected, -tilt_angle, image_center)
|
| 217 |
-
|
| 218 |
-
midline_start = (int(midline_points_display[0, 0]), int(midline_points_display[0, 1]))
|
| 219 |
-
midline_end = (int(midline_points_display[1, 0]), int(midline_points_display[1, 1]))
|
| 220 |
-
|
| 221 |
-
# Draw dashed line by drawing short segments
|
| 222 |
-
dash_length = 10
|
| 223 |
-
gap_length = 5
|
| 224 |
-
total_length = np.sqrt((midline_end[0] - midline_start[0])**2 + (midline_end[1] - midline_start[1])**2)
|
| 225 |
-
num_segments = int(total_length / (dash_length + gap_length))
|
| 226 |
-
|
| 227 |
-
for i in range(0, num_segments, 2): # Every other segment for dashed effect
|
| 228 |
-
start_ratio = i * (dash_length + gap_length) / total_length
|
| 229 |
-
end_ratio = (i * (dash_length + gap_length) + dash_length) / total_length
|
| 230 |
-
if end_ratio > 1:
|
| 231 |
-
end_ratio = 1
|
| 232 |
-
|
| 233 |
-
dash_start = (
|
| 234 |
-
int(midline_start[0] + start_ratio * (midline_end[0] - midline_start[0])),
|
| 235 |
-
int(midline_start[1] + start_ratio * (midline_end[1] - midline_start[1]))
|
| 236 |
-
)
|
| 237 |
-
dash_end = (
|
| 238 |
-
int(midline_start[0] + end_ratio * (midline_end[0] - midline_start[0])),
|
| 239 |
-
int(midline_start[1] + end_ratio * (midline_end[1] - midline_start[1]))
|
| 240 |
-
)
|
| 241 |
-
image = cv2.line(image, dash_start, dash_end, (1, 1, 1), 2)
|
| 242 |
-
|
| 243 |
-
# Draw bilateral measurement lines
|
| 244 |
-
# Left side cardiac measurement (cyan)
|
| 245 |
-
left_cardiac_points = np.array([[thorax_midline_corrected, heart_y_corrected], [heart_xmin_corrected, heart_y_corrected]])
|
| 246 |
-
left_cardiac_display = rotate_points(left_cardiac_points, -tilt_angle, image_center)
|
| 247 |
-
image = cv2.line(image,
|
| 248 |
-
(int(left_cardiac_display[0, 0]), int(left_cardiac_display[0, 1])),
|
| 249 |
-
(int(left_cardiac_display[1, 0]), int(left_cardiac_display[1, 1])),
|
| 250 |
-
(0, 1, 1), 2)
|
| 251 |
-
|
| 252 |
-
# Right side cardiac measurement (yellow)
|
| 253 |
-
right_cardiac_points = np.array([[thorax_midline_corrected, heart_y_corrected], [heart_xmax_corrected, heart_y_corrected]])
|
| 254 |
-
right_cardiac_display = rotate_points(right_cardiac_points, -tilt_angle, image_center)
|
| 255 |
-
image = cv2.line(image,
|
| 256 |
-
(int(right_cardiac_display[0, 0]), int(right_cardiac_display[0, 1])),
|
| 257 |
-
(int(right_cardiac_display[1, 0]), int(right_cardiac_display[1, 1])),
|
| 258 |
-
(1, 1, 0), 2)
|
| 259 |
-
|
| 260 |
# Store corrected landmarks for CTR calculation
|
| 261 |
return image, (RL_corrected, LL_corrected, H_corrected, tilt_angle)
|
| 262 |
|
|
@@ -375,7 +325,7 @@ def validate_landmarks_consistency(landmarks, original_landmarks, threshold=0.05
|
|
| 375 |
return False
|
| 376 |
|
| 377 |
def calculate_ctr_robust(landmarks, corrected_landmarks=None):
|
| 378 |
-
"""Calculate CTR with multiple validation steps
|
| 379 |
try:
|
| 380 |
original_landmarks = landmarks.copy()
|
| 381 |
|
|
@@ -403,33 +353,9 @@ def calculate_ctr_robust(landmarks, corrected_landmarks=None):
|
|
| 403 |
tilt_angle = 0
|
| 404 |
correction_applied = False
|
| 405 |
|
| 406 |
-
# Calculate thoracic midline for bilateral analysis
|
| 407 |
-
thoracic_left_edge = min(np.min(RL[:, 0]), np.min(LL[:, 0]))
|
| 408 |
-
thoracic_right_edge = max(np.max(RL[:, 0]), np.max(LL[:, 0]))
|
| 409 |
-
thoracic_midline = (thoracic_left_edge + thoracic_right_edge) / 2
|
| 410 |
-
thoracic_width = thoracic_right_edge - thoracic_left_edge
|
| 411 |
-
|
| 412 |
-
# Calculate cardiac boundaries
|
| 413 |
-
cardiac_left_edge = np.min(H[:, 0])
|
| 414 |
-
cardiac_right_edge = np.max(H[:, 0])
|
| 415 |
-
cardiac_center = np.mean(H[:, 0])
|
| 416 |
-
cardiac_width = cardiac_right_edge - cardiac_left_edge
|
| 417 |
-
|
| 418 |
-
# === BILATERAL CTR ANALYSIS ===
|
| 419 |
-
# Left-side measurements (from thoracic midline to left edge)
|
| 420 |
-
left_thoracic_width = thoracic_midline - thoracic_left_edge
|
| 421 |
-
left_cardiac_width = thoracic_midline - cardiac_left_edge
|
| 422 |
-
left_ctr = left_cardiac_width / left_thoracic_width if left_thoracic_width > 0 else 0
|
| 423 |
-
|
| 424 |
-
# Right-side measurements (from thoracic midline to right edge)
|
| 425 |
-
right_thoracic_width = thoracic_right_edge - thoracic_midline
|
| 426 |
-
right_cardiac_width = cardiac_right_edge - thoracic_midline
|
| 427 |
-
right_ctr = right_cardiac_width / right_thoracic_width if right_thoracic_width > 0 else 0
|
| 428 |
-
|
| 429 |
-
# === TRADITIONAL TOTAL CTR METHODS ===
|
| 430 |
# Method 1: Traditional width measurement
|
| 431 |
-
cardiac_width_1 =
|
| 432 |
-
thoracic_width_1 =
|
| 433 |
|
| 434 |
# Method 2: Centroid-based measurement (more robust to outliers)
|
| 435 |
h_centroid = np.mean(H, axis=0)
|
|
@@ -440,7 +366,7 @@ def calculate_ctr_robust(landmarks, corrected_landmarks=None):
|
|
| 440 |
h_distances = np.linalg.norm(H - h_centroid, axis=1)
|
| 441 |
cardiac_width_2 = 2 * np.max(h_distances)
|
| 442 |
|
| 443 |
-
thoracic_width_2 =
|
| 444 |
|
| 445 |
# Method 3: Percentile-based measurement (removes extreme outliers)
|
| 446 |
cardiac_x_coords = H[:, 0]
|
|
@@ -469,22 +395,6 @@ def calculate_ctr_robust(landmarks, corrected_landmarks=None):
|
|
| 469 |
# Use median of methods for final result
|
| 470 |
final_ctr = np.median(ctr_values)
|
| 471 |
|
| 472 |
-
# === ASYMMETRY ANALYSIS ===
|
| 473 |
-
# Calculate cardiac asymmetry ratio (how much heart deviates to one side)
|
| 474 |
-
cardiac_shift = cardiac_center - thoracic_midline
|
| 475 |
-
cardiac_asymmetry_ratio = abs(cardiac_shift) / (thoracic_width / 2) if thoracic_width > 0 else 0
|
| 476 |
-
|
| 477 |
-
# Determine which side the heart is shifted towards
|
| 478 |
-
if cardiac_shift > thoracic_width * 0.02: # > 2% of thoracic width
|
| 479 |
-
heart_position = "Right-shifted"
|
| 480 |
-
elif cardiac_shift < -thoracic_width * 0.02: # < -2% of thoracic width
|
| 481 |
-
heart_position = "Left-shifted"
|
| 482 |
-
else:
|
| 483 |
-
heart_position = "Centered"
|
| 484 |
-
|
| 485 |
-
# Calculate bilateral ratio (left CTR / right CTR)
|
| 486 |
-
bilateral_ratio = left_ctr / right_ctr if right_ctr > 0 else 0
|
| 487 |
-
|
| 488 |
return {
|
| 489 |
'ctr': round(final_ctr, 3),
|
| 490 |
'tilt_angle': abs(tilt_angle),
|
|
@@ -495,17 +405,6 @@ def calculate_ctr_robust(landmarks, corrected_landmarks=None):
|
|
| 495 |
'traditional': round(ctr_1, 3),
|
| 496 |
'centroid': round(ctr_2, 3),
|
| 497 |
'percentile': round(ctr_3, 3)
|
| 498 |
-
},
|
| 499 |
-
# New bilateral analysis results
|
| 500 |
-
'bilateral_analysis': {
|
| 501 |
-
'left_ctr': round(left_ctr, 3),
|
| 502 |
-
'right_ctr': round(right_ctr, 3),
|
| 503 |
-
'bilateral_ratio': round(bilateral_ratio, 3),
|
| 504 |
-
'cardiac_asymmetry_ratio': round(cardiac_asymmetry_ratio, 3),
|
| 505 |
-
'heart_position': heart_position,
|
| 506 |
-
'thoracic_midline_x': round(thoracic_midline, 1),
|
| 507 |
-
'cardiac_center_x': round(cardiac_center, 1),
|
| 508 |
-
'cardiac_shift_px': round(cardiac_shift, 1)
|
| 509 |
}
|
| 510 |
}
|
| 511 |
|
|
@@ -517,17 +416,7 @@ def calculate_ctr_robust(landmarks, corrected_landmarks=None):
|
|
| 517 |
'correction_applied': False,
|
| 518 |
'confidence': 'Error',
|
| 519 |
'method_variance': 0,
|
| 520 |
-
'individual_results': {}
|
| 521 |
-
'bilateral_analysis': {
|
| 522 |
-
'left_ctr': 0,
|
| 523 |
-
'right_ctr': 0,
|
| 524 |
-
'bilateral_ratio': 0,
|
| 525 |
-
'cardiac_asymmetry_ratio': 0,
|
| 526 |
-
'heart_position': 'Unknown',
|
| 527 |
-
'thoracic_midline_x': 0,
|
| 528 |
-
'cardiac_center_x': 0,
|
| 529 |
-
'cardiac_shift_px': 0
|
| 530 |
-
}
|
| 531 |
}
|
| 532 |
|
| 533 |
|
|
@@ -690,9 +579,8 @@ def segment(input_img):
|
|
| 690 |
|
| 691 |
except Exception as e:
|
| 692 |
print(f"Error in segmentation: {e}")
|
| 693 |
-
# Return a basic error response
|
| 694 |
-
|
| 695 |
-
return None, None, 0, 0, 0, 0, 0, "Error", error_msg
|
| 696 |
|
| 697 |
seg_to_save = (outseg.copy() * 255).astype('uint8')
|
| 698 |
cv2.imwrite("tmp/overlap_segmentation.png", cv2.cvtColor(seg_to_save, cv2.COLOR_RGB2BGR))
|
|
@@ -701,7 +589,6 @@ def segment(input_img):
|
|
| 701 |
ctr_result = calculate_ctr_robust(output, corrected_data)
|
| 702 |
ctr_value = ctr_result['ctr']
|
| 703 |
tilt_angle = ctr_result['tilt_angle']
|
| 704 |
-
bilateral = ctr_result['bilateral_analysis']
|
| 705 |
|
| 706 |
# Enhanced interpretation with quality indicators
|
| 707 |
interpretation_parts = []
|
|
@@ -720,22 +607,6 @@ def segment(input_img):
|
|
| 720 |
|
| 721 |
interpretation_parts.append(base_interpretation)
|
| 722 |
|
| 723 |
-
# Add bilateral analysis
|
| 724 |
-
bilateral_parts = []
|
| 725 |
-
bilateral_parts.append(f"L-CTR: {bilateral['left_ctr']}")
|
| 726 |
-
bilateral_parts.append(f"R-CTR: {bilateral['right_ctr']}")
|
| 727 |
-
bilateral_parts.append(f"L/R Ratio: {bilateral['bilateral_ratio']}")
|
| 728 |
-
|
| 729 |
-
# Analyze cardiac position
|
| 730 |
-
if bilateral['heart_position'] != 'Centered':
|
| 731 |
-
bilateral_parts.append(f"Heart: {bilateral['heart_position']}")
|
| 732 |
-
|
| 733 |
-
# Check for significant asymmetry
|
| 734 |
-
if bilateral['cardiac_asymmetry_ratio'] > 0.1:
|
| 735 |
-
bilateral_parts.append(f"Asymmetry: {bilateral['cardiac_asymmetry_ratio']:.2f}")
|
| 736 |
-
|
| 737 |
-
interpretation_parts.append(" | ".join(bilateral_parts))
|
| 738 |
-
|
| 739 |
# Add quality indicators
|
| 740 |
if was_rotated:
|
| 741 |
interpretation_parts.append(f"Image rotation corrected ({detected_rotation:.1f}°)")
|
|
@@ -748,19 +619,9 @@ def segment(input_img):
|
|
| 748 |
# Add confidence indicator
|
| 749 |
interpretation_parts.append(f"Confidence: {ctr_result['confidence']}")
|
| 750 |
|
| 751 |
-
final_interpretation = "
|
| 752 |
|
| 753 |
-
|
| 754 |
-
|
| 755 |
-
return (outseg,
|
| 756 |
-
"tmp/overlap_segmentation.png",
|
| 757 |
-
ctr_result['ctr'], # Total CTR
|
| 758 |
-
bilateral['left_ctr'], # Left CTR
|
| 759 |
-
bilateral['right_ctr'], # Right CTR
|
| 760 |
-
bilateral['bilateral_ratio'], # L/R Ratio
|
| 761 |
-
bilateral['cardiac_asymmetry_ratio'], # Asymmetry
|
| 762 |
-
bilateral['heart_position'], # Heart Position
|
| 763 |
-
final_interpretation) # Clinical Interpretation
|
| 764 |
|
| 765 |
|
| 766 |
if __name__ == "__main__":
|
|
@@ -796,16 +657,8 @@ if __name__ == "__main__":
|
|
| 796 |
image_output = gr.Image(type="filepath", height=750)
|
| 797 |
|
| 798 |
with gr.Row():
|
| 799 |
-
|
| 800 |
-
|
| 801 |
-
ctr_left = gr.Number(label="Left CTR", precision=3)
|
| 802 |
-
ctr_right = gr.Number(label="Right CTR", precision=3)
|
| 803 |
-
with gr.Column():
|
| 804 |
-
bilateral_ratio = gr.Number(label="L/R Ratio", precision=3)
|
| 805 |
-
asymmetry_ratio = gr.Number(label="Asymmetry", precision=3)
|
| 806 |
-
heart_position = gr.Textbox(label="Heart Position", interactive=False)
|
| 807 |
-
|
| 808 |
-
ctr_interpretation = gr.Textbox(label="Clinical Interpretation", interactive=False, lines=4)
|
| 809 |
|
| 810 |
results = gr.File()
|
| 811 |
|
|
@@ -852,8 +705,9 @@ if __name__ == "__main__":
|
|
| 852 |
|
| 853 |
clear_button.click(lambda: None, None, image_input, queue=False)
|
| 854 |
clear_button.click(lambda: None, None, image_output, queue=False)
|
| 855 |
-
clear_button.click(lambda:
|
|
|
|
| 856 |
|
| 857 |
-
image_button.click(segment, inputs=image_input, outputs=[image_output, results,
|
| 858 |
|
| 859 |
demo.launch()
|
|
|
|
| 131 |
# Draw measurement lines that follow the image tilt for visual accuracy
|
| 132 |
# Use corrected coordinates for accurate measurement, but draw tilted lines for visual appeal
|
| 133 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
# Heart (red line) - calculate positions from corrected coordinates
|
| 135 |
heart_xmin_corrected = np.min(H_corrected[:, 0])
|
| 136 |
heart_xmax_corrected = np.max(H_corrected[:, 0])
|
|
|
|
| 166 |
(1, 0, 0), 2)
|
| 167 |
|
| 168 |
# Thorax (blue line) - calculate positions from corrected coordinates
|
| 169 |
+
thorax_xmin_corrected = min(np.min(RL_corrected[:, 0]), np.min(LL_corrected[:, 0]))
|
| 170 |
+
thorax_xmax_corrected = max(np.max(RL_corrected[:, 0]), np.max(LL_corrected[:, 0]))
|
| 171 |
+
|
| 172 |
# Find y at leftmost and rightmost points (corrected)
|
| 173 |
if np.min(RL_corrected[:, 0]) < np.min(LL_corrected[:, 0]):
|
| 174 |
thorax_ymin_corrected = RL_corrected[np.argmin(RL_corrected[:, 0]), 1]
|
|
|
|
| 207 |
(int(thorax_end[0] - perp_x), int(thorax_end[1] - perp_y)),
|
| 208 |
(0, 0, 1), 2)
|
| 209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
# Store corrected landmarks for CTR calculation
|
| 211 |
return image, (RL_corrected, LL_corrected, H_corrected, tilt_angle)
|
| 212 |
|
|
|
|
| 325 |
return False
|
| 326 |
|
| 327 |
def calculate_ctr_robust(landmarks, corrected_landmarks=None):
|
| 328 |
+
"""Calculate CTR with multiple validation steps"""
|
| 329 |
try:
|
| 330 |
original_landmarks = landmarks.copy()
|
| 331 |
|
|
|
|
| 353 |
tilt_angle = 0
|
| 354 |
correction_applied = False
|
| 355 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 356 |
# Method 1: Traditional width measurement
|
| 357 |
+
cardiac_width_1 = np.max(H[:, 0]) - np.min(H[:, 0])
|
| 358 |
+
thoracic_width_1 = max(np.max(RL[:, 0]), np.max(LL[:, 0])) - min(np.min(RL[:, 0]), np.min(LL[:, 0]))
|
| 359 |
|
| 360 |
# Method 2: Centroid-based measurement (more robust to outliers)
|
| 361 |
h_centroid = np.mean(H, axis=0)
|
|
|
|
| 366 |
h_distances = np.linalg.norm(H - h_centroid, axis=1)
|
| 367 |
cardiac_width_2 = 2 * np.max(h_distances)
|
| 368 |
|
| 369 |
+
thoracic_width_2 = max(np.max(RL[:, 0]), np.max(LL[:, 0])) - min(np.min(RL[:, 0]), np.min(LL[:, 0]))
|
| 370 |
|
| 371 |
# Method 3: Percentile-based measurement (removes extreme outliers)
|
| 372 |
cardiac_x_coords = H[:, 0]
|
|
|
|
| 395 |
# Use median of methods for final result
|
| 396 |
final_ctr = np.median(ctr_values)
|
| 397 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
return {
|
| 399 |
'ctr': round(final_ctr, 3),
|
| 400 |
'tilt_angle': abs(tilt_angle),
|
|
|
|
| 405 |
'traditional': round(ctr_1, 3),
|
| 406 |
'centroid': round(ctr_2, 3),
|
| 407 |
'percentile': round(ctr_3, 3)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
}
|
| 409 |
}
|
| 410 |
|
|
|
|
| 416 |
'correction_applied': False,
|
| 417 |
'confidence': 'Error',
|
| 418 |
'method_variance': 0,
|
| 419 |
+
'individual_results': {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 420 |
}
|
| 421 |
|
| 422 |
|
|
|
|
| 579 |
|
| 580 |
except Exception as e:
|
| 581 |
print(f"Error in segmentation: {e}")
|
| 582 |
+
# Return a basic error response
|
| 583 |
+
return None, None, 0, f"Error: {str(e)}"
|
|
|
|
| 584 |
|
| 585 |
seg_to_save = (outseg.copy() * 255).astype('uint8')
|
| 586 |
cv2.imwrite("tmp/overlap_segmentation.png", cv2.cvtColor(seg_to_save, cv2.COLOR_RGB2BGR))
|
|
|
|
| 589 |
ctr_result = calculate_ctr_robust(output, corrected_data)
|
| 590 |
ctr_value = ctr_result['ctr']
|
| 591 |
tilt_angle = ctr_result['tilt_angle']
|
|
|
|
| 592 |
|
| 593 |
# Enhanced interpretation with quality indicators
|
| 594 |
interpretation_parts = []
|
|
|
|
| 607 |
|
| 608 |
interpretation_parts.append(base_interpretation)
|
| 609 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 610 |
# Add quality indicators
|
| 611 |
if was_rotated:
|
| 612 |
interpretation_parts.append(f"Image rotation corrected ({detected_rotation:.1f}°)")
|
|
|
|
| 619 |
# Add confidence indicator
|
| 620 |
interpretation_parts.append(f"Confidence: {ctr_result['confidence']}")
|
| 621 |
|
| 622 |
+
final_interpretation = " | ".join(interpretation_parts)
|
| 623 |
|
| 624 |
+
return outseg, "tmp/overlap_segmentation.png", ctr_value, final_interpretation
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 625 |
|
| 626 |
|
| 627 |
if __name__ == "__main__":
|
|
|
|
| 657 |
image_output = gr.Image(type="filepath", height=750)
|
| 658 |
|
| 659 |
with gr.Row():
|
| 660 |
+
ctr_output = gr.Number(label="CTR (Cardiothoracic Ratio)")
|
| 661 |
+
ctr_interpretation = gr.Textbox(label="Interpretation", interactive=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 662 |
|
| 663 |
results = gr.File()
|
| 664 |
|
|
|
|
| 705 |
|
| 706 |
clear_button.click(lambda: None, None, image_input, queue=False)
|
| 707 |
clear_button.click(lambda: None, None, image_output, queue=False)
|
| 708 |
+
clear_button.click(lambda: None, None, ctr_output, queue=False)
|
| 709 |
+
clear_button.click(lambda: None, None, ctr_interpretation, queue=False)
|
| 710 |
|
| 711 |
+
image_button.click(segment, inputs=image_input, outputs=[image_output, results, ctr_output, ctr_interpretation], queue=False)
|
| 712 |
|
| 713 |
demo.launch()
|