y512 commited on
Commit
1a80759
·
verified ·
1 Parent(s): cee6470

Update app.py

Browse files

UI/UX Refactoring and Deployment Optimization

1. Localization & Medical Terminology

Full English Translation: Translated the entire Gradio interface into English to align with international academic and clinical standards.

Professional Terminology: Upgraded standard variable names and outputs to professional medical terminology (e.g., Clinical Assessment, Anatomical Landmarks, Acetabular Index).

2. UI/UX Enhancements & Layout

Aesthetic Theme: Applied the gr.themes.Soft() theme to provide a clean, calming, and professional visual experience suitable for a healthcare application.

Layout Restructuring: Redesigned the interface into a logical two-column layout using gr.Row() and gr.Column(). The left column acts as the "Input Panel," and the right column serves as the "Diagnostic Output," significantly improving the user workflow.

Progressive Disclosure: Encapsulated advanced model parameters (like the Confidence Threshold slider) within an interactive gr.Accordion. This keeps the primary interface uncluttered for medical end-users while remaining accessible for engineers.

3. Enhanced Result Formatting

Markdown Integration: Upgraded the diagnostic output from plain text to rich Markdown format.

Visual Hierarchy: Clinical metrics (such as exact angles and severity levels) are now highlighted in bold, and visual indicators (emojis) were introduced to allow physicians to quickly assess the severity of the dysplasia at a glance.

4. Cloud Deployment Fixes

Hugging Face Compatibility: Modified the demo.launch() execution block by defining explicit server bindings (server_name="0.0.0.0", server_port=7860). This resolves the local-host access error and ensures seamless, stable execution on Hugging Face Spaces.

Files changed (1) hide show
  1. app.py +121 -92
app.py CHANGED
@@ -1,92 +1,121 @@
1
- import gradio as gr
2
- import cv2
3
- import numpy as np
4
- import math
5
- from ultralytics import YOLO
6
-
7
- # تحميل الموديل
8
- MODEL_PATH = "best.pt"
9
- model = YOLO(MODEL_PATH, task="pose")
10
-
11
- def get_hip_points(image_crop, model, conf=0.25):
12
- results = model(image_crop, conf=conf, verbose=False)
13
- for r in results:
14
- if r.keypoints and r.keypoints.shape[1] >= 2:
15
- kpts = r.keypoints.xy[0].cpu().numpy().astype(int)
16
- valid_kpts = [p for p in kpts if p[0] != 0 and p[1] != 0]
17
- if len(valid_kpts) >= 2:
18
- valid_kpts.sort(key=lambda p: p[1])
19
- return valid_kpts[-1], valid_kpts[0]
20
- return None, None
21
-
22
- def calculate_slope_angle(center, rim, other_center):
23
- try:
24
- if other_center[0] - center[0] == 0: m_h = 0
25
- else: m_h = (other_center[1] - center[1]) / (other_center[0] - center[0])
26
- if rim[0] - center[0] == 0: m_r = 1e9
27
- else: m_r = (rim[1] - center[1]) / (rim[0] - center[0])
28
- tan_theta = abs((m_r - m_h) / (1 + m_h * m_r))
29
- return math.degrees(math.atan(tan_theta))
30
- except: return 0.0
31
-
32
- def get_diagnosis_style(angle):
33
- # ملاحظة: هون بتقدر تعدل الدرجات لـ 4 حسب مشروعك
34
- if angle >= 30: return "Dysplasia (Severity High)", "#FF4B4B"
35
- if angle >= 25: return "Borderline / Mild", "#FFA500"
36
- return "Normal", "#09AB3B"
37
-
38
- def analyze_xray(input_img, conf):
39
- image = np.array(input_img)
40
- image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
41
- h, w, _ = image.shape
42
- mid_x = w // 2
43
-
44
- right_hip_img = image[:, :mid_x]
45
- left_hip_img = image[:, mid_x:]
46
-
47
- r_tri, r_rim = get_hip_points(right_hip_img, model, conf)
48
- l_tri_local, l_rim_local = get_hip_points(left_hip_img, model, conf)
49
-
50
- if r_tri is None or l_tri_local is None:
51
- return image, "Could not detect landmarks. Try lowering confidence."
52
-
53
- l_tri_global = (l_tri_local[0] + mid_x, l_tri_local[1])
54
- l_rim_global = (l_rim_local[0] + mid_x, l_rim_local[1])
55
-
56
- # الرسم (نفس المنطق تبعك)
57
- cv2.line(image, tuple(r_tri), tuple(l_tri_global), (0, 255, 255), 3)
58
-
59
- ang_r = calculate_slope_angle(r_tri, r_rim, l_tri_global)
60
- diag_r, color_r = get_diagnosis_style(ang_r)
61
-
62
- ang_l = calculate_slope_angle(l_tri_global, l_rim_global, r_tri)
63
- diag_l, color_l = get_diagnosis_style(ang_l)
64
-
65
- # إضافة النصوص على الصورة أو إرجاعها كـ Markdown
66
- result_text = f"## 🦴 Diagnosis Results:\n"
67
- result_text += f"**Right Hip:** {ang_r:.1f}° - {diag_r}\n\n"
68
- result_text += f"**Left Hip:** {ang_l:.1f}° - {diag_l}"
69
-
70
- # رسم النقاط والخطوط
71
- cv2.line(image, tuple(r_tri), tuple(r_rim), (0, 0, 255), 3)
72
- cv2.line(image, tuple(l_tri_global), tuple(l_rim_global), (0, 0, 255), 3)
73
-
74
- return cv2.cvtColor(image, cv2.COLOR_BGR2RGB), result_text
75
-
76
- # واجهة Gradio
77
- with gr.Blocks(title="DDH AI Expert") as demo:
78
- gr.Markdown("# 🏥 DDH AI Expert System")
79
- gr.Markdown("قم برفع صورة X-ray لحوض الطفل للكشف التلقائي عن خلع الولادة.")
80
-
81
- with gr.Row():
82
- with gr.Column():
83
- input_img = gr.Image(type="pil", label="Upload X-ray")
84
- conf_slider = gr.Slider(0.1, 1.0, value=0.25, label="Confidence Threshold")
85
- btn = gr.Button("Analyze Image")
86
- with gr.Column():
87
- output_img = gr.Image(label="Processed Image")
88
- output_text = gr.Markdown()
89
-
90
- btn.click(analyze_xray, inputs=[input_img, conf_slider], outputs=[output_img, output_text])
91
-
92
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import cv2
3
+ import numpy as np
4
+ import math
5
+ from ultralytics import YOLO
6
+
7
+ # Load Model
8
+ MODEL_PATH = "best.pt"
9
+ model = YOLO(MODEL_PATH, task="pose")
10
+
11
+ def get_hip_points(image_crop, model, conf=0.25):
12
+ results = model(image_crop, conf=conf, verbose=False)
13
+ for r in results:
14
+ if r.keypoints and r.keypoints.shape[1] >= 2:
15
+ kpts = r.keypoints.xy[0].cpu().numpy().astype(int)
16
+ valid_kpts = [p for p in kpts if p[0] != 0 and p[1] != 0]
17
+ if len(valid_kpts) >= 2:
18
+ valid_kpts.sort(key=lambda p: p[1])
19
+ return valid_kpts[-1], valid_kpts[0]
20
+ return None, None
21
+
22
+ def calculate_slope_angle(center, rim, other_center):
23
+ try:
24
+ if other_center[0] - center[0] == 0: m_h = 0
25
+ else: m_h = (other_center[1] - center[1]) / (other_center[0] - center[0])
26
+ if rim[0] - center[0] == 0: m_r = 1e9
27
+ else: m_r = (rim[1] - center[1]) / (rim[0] - center[0])
28
+ tan_theta = abs((m_r - m_h) / (1 + m_h * m_r))
29
+ return math.degrees(math.atan(tan_theta))
30
+ except: return 0.0
31
+
32
+ def get_diagnosis_style(angle):
33
+ if angle >= 30: return "Dysplasia (High Severity)", "#FF4B4B"
34
+ if angle >= 25: return "Borderline / Mild", "#FFA500"
35
+ return "Normal", "#09AB3B"
36
+
37
+ def analyze_xray(input_img, conf):
38
+ image = np.array(input_img)
39
+ image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
40
+ h, w, _ = image.shape
41
+ mid_x = w // 2
42
+
43
+ right_hip_img = image[:, :mid_x]
44
+ left_hip_img = image[:, mid_x:]
45
+
46
+ r_tri, r_rim = get_hip_points(right_hip_img, model, conf)
47
+ l_tri_local, l_rim_local = get_hip_points(left_hip_img, model, conf)
48
+
49
+ if r_tri is None or l_tri_local is None:
50
+ return image, "⚠️ **Error:** Could not detect anatomical landmarks. Try adjusting the confidence threshold."
51
+
52
+ l_tri_global = (l_tri_local[0] + mid_x, l_tri_local[1])
53
+ l_rim_global = (l_rim_local[0] + mid_x, l_rim_local[1])
54
+
55
+ # Draw Hilgenreiner's line (Base Line)
56
+ cv2.line(image, tuple(r_tri), tuple(l_tri_global), (0, 255, 255), 3)
57
+
58
+ ang_r = calculate_slope_angle(r_tri, r_rim, l_tri_global)
59
+ diag_r, color_r = get_diagnosis_style(ang_r)
60
+
61
+ ang_l = calculate_slope_angle(l_tri_global, l_rim_global, r_tri)
62
+ diag_l, color_l = get_diagnosis_style(ang_l)
63
+
64
+ # Formatting the output text with Markdown
65
+ result_text = f"### 🩺 Clinical Assessment Results\n\n"
66
+ result_text += f"**Right Hip AI:** `{ang_r:.1f}°` ➔ **{diag_r}**\n\n"
67
+ result_text += f"**Left Hip AI:** `{ang_l:.1f}°` **{diag_l}**"
68
+
69
+ # Draw Roof Lines
70
+ cv2.line(image, tuple(r_tri), tuple(r_rim), (0, 0, 255), 3)
71
+ cv2.line(image, tuple(l_tri_global), tuple(l_rim_global), (0, 0, 255), 3)
72
+
73
+ return cv2.cvtColor(image, cv2.COLOR_BGR2RGB), result_text
74
+
75
+ # ==========================================
76
+ # Gradio UI Design (Enhanced & English)
77
+ # ==========================================
78
+ custom_theme = gr.themes.Soft(
79
+ primary_hue="blue",
80
+ secondary_hue="slate",
81
+ )
82
+
83
+ with gr.Blocks(title="DislocPred: DDH System", theme=custom_theme) as demo:
84
+
85
+ # Header Section
86
+ with gr.Row():
87
+ gr.Markdown(
88
+ """
89
+ # 🏥 DislocPred: AI Diagnostic Assistant
90
+ **Automated Detection & Grading for Developmental Dysplasia of the Hip (DDH)** Upload a pediatric pelvic X-ray (AP view). The system will analyze the anatomical landmarks, calculate the Acetabular Index (AI), and provide a clinical evaluation.
91
+ """
92
+ )
93
+
94
+ # Main Application Area
95
+ with gr.Row():
96
+ # Left Column: Inputs
97
+ with gr.Column(scale=1):
98
+ gr.Markdown("### 📥 Input Panel")
99
+ input_img = gr.Image(type="pil", label="Upload X-ray Image")
100
+
101
+ with gr.Accordion("⚙️ Advanced Model Settings", open=False):
102
+ conf_slider = gr.Slider(0.1, 1.0, value=0.25, step=0.05, label="Detection Confidence Threshold")
103
+
104
+ btn = gr.Button("🔍 Run AI Analysis", variant="primary")
105
+
106
+ # Right Column: Outputs
107
+ with gr.Column(scale=1):
108
+ gr.Markdown("### 📤 Diagnostic Output")
109
+ output_img = gr.Image(label="Annotated Radiograph")
110
+ output_text = gr.Markdown(label="Results")
111
+
112
+ # Connect logic to UI
113
+ btn.click(
114
+ fn=analyze_xray,
115
+ inputs=[input_img, conf_slider],
116
+ outputs=[output_img, output_text]
117
+ )
118
+
119
+ # Launch with proper Hugging Face settings
120
+ if __name__ == "__main__":
121
+ demo.launch(server_name="0.0.0.0", server_port=7860)