Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -59,7 +59,6 @@ def analyze_gait(video_file):
|
|
| 59 |
|
| 60 |
L_clear, R_clear, L_angle, R_angle = [], [], [], []
|
| 61 |
base_seq, tilt_seq, side_lean_seq = [], [], []
|
| 62 |
-
|
| 63 |
frames, person_detected = 0, False
|
| 64 |
|
| 65 |
while cap.isOpened() and frames < 1000:
|
|
@@ -99,7 +98,6 @@ def analyze_gait(video_file):
|
|
| 99 |
if not person_detected:
|
| 100 |
return "<div style='direction:rtl;text-align:right'>❌ لم يتم اكتشاف شخص في الفيديو. يُرجى إعادة التصوير بزاوية أمامية واضحة.</div>", "<div></div>"
|
| 101 |
|
| 102 |
-
# حساب الإحصاءات
|
| 103 |
avg_Lc, avg_Rc = _safe_mean(L_clear), _safe_mean(R_clear)
|
| 104 |
std_Lc, std_Rc = _safe_std(L_clear), _safe_std(R_clear)
|
| 105 |
avg_La, avg_Ra = _safe_mean(L_angle), _safe_mean(R_angle)
|
|
@@ -107,42 +105,30 @@ def analyze_gait(video_file):
|
|
| 107 |
avg_lean = _safe_mean(side_lean_seq)
|
| 108 |
base_ratio = _safe_mean(base_seq)/W
|
| 109 |
|
| 110 |
-
# فروقات وتشتت
|
| 111 |
diff_clear = abs(avg_Lc - avg_Rc)
|
| 112 |
diff_angle = abs(avg_La - avg_Ra)
|
| 113 |
var_clear = max(std_Lc, std_Rc)
|
| 114 |
-
|
| 115 |
-
# حساب مؤشرات التماثل
|
| 116 |
sym_clear = abs((avg_Lc - avg_Rc) / (avg_Lc + avg_Rc + 1e-6)) * 100
|
| 117 |
sym_angle = abs((avg_La - avg_Ra) / (avg_La + avg_Ra + 1e-6)) * 100
|
| 118 |
-
|
| 119 |
-
# نسب انخفاض الارتفاع
|
| 120 |
low_ratio_L = np.mean(np.array(L_clear) < 4)
|
| 121 |
low_ratio_R = np.mean(np.array(R_clear) < 4)
|
| 122 |
|
| 123 |
-
# =============================
|
| 124 |
-
# منطق التقييم الصارم
|
| 125 |
-
# =============================
|
| 126 |
score = 0
|
| 127 |
red_flags = 0
|
| 128 |
|
| 129 |
if min(avg_Lc, avg_Rc) < 4 or low_ratio_L > 0.4 or low_ratio_R > 0.4:
|
| 130 |
-
score += 3.5; red_flags += 1
|
| 131 |
if var_clear > 8 or diff_angle > 15 or sym_angle > 18:
|
| 132 |
-
score += 3; red_flags += 1
|
| 133 |
if base_ratio > 0.24 and avg_tilt > 8:
|
| 134 |
-
score += 3.5; red_flags += 1
|
| 135 |
-
if sym_clear > 25:
|
| 136 |
-
|
| 137 |
-
if
|
| 138 |
-
score += 1.5 # ميل جذع غير متزن
|
| 139 |
-
if diff_clear > 5 and diff_angle > 10:
|
| 140 |
-
score += 1.0
|
| 141 |
|
| 142 |
score = min(score, 10)
|
| 143 |
norm_score = score / 10.0
|
| 144 |
|
| 145 |
-
# تحديد الجانب المصاب
|
| 146 |
if avg_Lc < avg_Rc-2 and avg_La < avg_Ra:
|
| 147 |
side = "اليسار"
|
| 148 |
elif avg_Rc < avg_Lc-2 and avg_Ra < avg_La:
|
|
@@ -150,13 +136,12 @@ def analyze_gait(video_file):
|
|
| 150 |
else:
|
| 151 |
side = "غير محدد"
|
| 152 |
|
| 153 |
-
# تصنيف النتيجة
|
| 154 |
if red_flags >= 2 or norm_score >= 0.7:
|
| 155 |
level, color, desc = "🔴 عالية الخطورة", "#c62828", "تم رصد مؤشرات متعددة لخلل واضح في المشية."
|
| 156 |
booking = """
|
| 157 |
<div style='margin-top:10px;direction:rtl;text-align:right'>
|
| 158 |
<a href="https://example.com/book" target="_blank"
|
| 159 |
-
style="background:#
|
| 160 |
احجز موعد مباشر (حضوري أو أونلاين)
|
| 161 |
</a>
|
| 162 |
</div>"""
|
|
@@ -165,7 +150,7 @@ def analyze_gait(video_file):
|
|
| 165 |
booking = """
|
| 166 |
<div style='margin-top:10px;direction:rtl;text-align:right'>
|
| 167 |
<a href="https://example.com/book" target="_blank"
|
| 168 |
-
style="background:#
|
| 169 |
احجز استشارة طبية
|
| 170 |
</a>
|
| 171 |
</div>"""
|
|
@@ -173,7 +158,6 @@ def analyze_gait(video_file):
|
|
| 173 |
level, color, desc = "🟢 طبيعية", "#2e7d32", "المشية ضمن النطاق السليم."
|
| 174 |
booking = ""
|
| 175 |
|
| 176 |
-
# تحديد الحالة المحتملة
|
| 177 |
if red_flags >= 3 and base_ratio > 0.25:
|
| 178 |
condition = "قدم شاركوت (Charcot Foot)"
|
| 179 |
elif min(avg_Lc, avg_Rc) < 4 or low_ratio_L > 0.4 or low_ratio_R > 0.4:
|
|
@@ -190,7 +174,7 @@ def analyze_gait(video_file):
|
|
| 190 |
<div>📊 درجة الخطورة: <b>{score:.1f}/10</b></div>
|
| 191 |
<div>{desc}</div>
|
| 192 |
{booking}
|
| 193 |
-
<div style='font-size:13px;color:#555;margin-top:8px'>⚠️ التحليل يعتمد على مؤشرات متعددة ولا يُغني عن الفحص الطبي.</div>
|
| 194 |
"""
|
| 195 |
return html, _gauge_html(norm_score)
|
| 196 |
|
|
@@ -209,18 +193,29 @@ instructions = """
|
|
| 209 |
</div>
|
| 210 |
"""
|
| 211 |
|
| 212 |
-
|
| 213 |
-
|
|
|
|
| 214 |
gr.HTML(instructions)
|
| 215 |
with gr.Row():
|
| 216 |
with gr.Column(scale=1):
|
| 217 |
video_in = gr.File(label="📂 اختر فيديو المشي", file_types=[".mp4", ".avi", ".mov"], type="binary")
|
| 218 |
-
analyze_btn = gr.Button("🔍 بدء التحليل",
|
| 219 |
with gr.Column(scale=1):
|
| 220 |
gauge = gr.HTML("<div></div>")
|
| 221 |
out_html = gr.HTML("<i style='direction:rtl;text-align:right'>النتيجة ستظهر هنا بعد التحليل...</i>")
|
| 222 |
analyze_btn.click(fn=analyze_gait, inputs=[video_in], outputs=[out_html, gauge])
|
| 223 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
if __name__ == "__main__":
|
| 225 |
demo.launch()
|
| 226 |
|
|
|
|
| 59 |
|
| 60 |
L_clear, R_clear, L_angle, R_angle = [], [], [], []
|
| 61 |
base_seq, tilt_seq, side_lean_seq = [], [], []
|
|
|
|
| 62 |
frames, person_detected = 0, False
|
| 63 |
|
| 64 |
while cap.isOpened() and frames < 1000:
|
|
|
|
| 98 |
if not person_detected:
|
| 99 |
return "<div style='direction:rtl;text-align:right'>❌ لم يتم اكتشاف شخص في الفيديو. يُرجى إعادة التصوير بزاوية أمامية واضحة.</div>", "<div></div>"
|
| 100 |
|
|
|
|
| 101 |
avg_Lc, avg_Rc = _safe_mean(L_clear), _safe_mean(R_clear)
|
| 102 |
std_Lc, std_Rc = _safe_std(L_clear), _safe_std(R_clear)
|
| 103 |
avg_La, avg_Ra = _safe_mean(L_angle), _safe_mean(R_angle)
|
|
|
|
| 105 |
avg_lean = _safe_mean(side_lean_seq)
|
| 106 |
base_ratio = _safe_mean(base_seq)/W
|
| 107 |
|
|
|
|
| 108 |
diff_clear = abs(avg_Lc - avg_Rc)
|
| 109 |
diff_angle = abs(avg_La - avg_Ra)
|
| 110 |
var_clear = max(std_Lc, std_Rc)
|
|
|
|
|
|
|
| 111 |
sym_clear = abs((avg_Lc - avg_Rc) / (avg_Lc + avg_Rc + 1e-6)) * 100
|
| 112 |
sym_angle = abs((avg_La - avg_Ra) / (avg_La + avg_Ra + 1e-6)) * 100
|
|
|
|
|
|
|
| 113 |
low_ratio_L = np.mean(np.array(L_clear) < 4)
|
| 114 |
low_ratio_R = np.mean(np.array(R_clear) < 4)
|
| 115 |
|
|
|
|
|
|
|
|
|
|
| 116 |
score = 0
|
| 117 |
red_flags = 0
|
| 118 |
|
| 119 |
if min(avg_Lc, avg_Rc) < 4 or low_ratio_L > 0.4 or low_ratio_R > 0.4:
|
| 120 |
+
score += 3.5; red_flags += 1
|
| 121 |
if var_clear > 8 or diff_angle > 15 or sym_angle > 18:
|
| 122 |
+
score += 3; red_flags += 1
|
| 123 |
if base_ratio > 0.24 and avg_tilt > 8:
|
| 124 |
+
score += 3.5; red_flags += 1
|
| 125 |
+
if sym_clear > 25: score += 1.5
|
| 126 |
+
if abs(avg_lean) > W*0.025: score += 1.5
|
| 127 |
+
if diff_clear > 5 and diff_angle > 10: score += 1.0
|
|
|
|
|
|
|
|
|
|
| 128 |
|
| 129 |
score = min(score, 10)
|
| 130 |
norm_score = score / 10.0
|
| 131 |
|
|
|
|
| 132 |
if avg_Lc < avg_Rc-2 and avg_La < avg_Ra:
|
| 133 |
side = "اليسار"
|
| 134 |
elif avg_Rc < avg_Lc-2 and avg_Ra < avg_La:
|
|
|
|
| 136 |
else:
|
| 137 |
side = "غير محدد"
|
| 138 |
|
|
|
|
| 139 |
if red_flags >= 2 or norm_score >= 0.7:
|
| 140 |
level, color, desc = "🔴 عالية الخطورة", "#c62828", "تم رصد مؤشرات متعددة لخلل واضح في المشية."
|
| 141 |
booking = """
|
| 142 |
<div style='margin-top:10px;direction:rtl;text-align:right'>
|
| 143 |
<a href="https://example.com/book" target="_blank"
|
| 144 |
+
style="background:#2e7d32;color:#fff;padding:10px 16px;border-radius:8px;text-decoration:none;font-weight:600;">
|
| 145 |
احجز موعد مباشر (حضوري أو أونلاين)
|
| 146 |
</a>
|
| 147 |
</div>"""
|
|
|
|
| 150 |
booking = """
|
| 151 |
<div style='margin-top:10px;direction:rtl;text-align:right'>
|
| 152 |
<a href="https://example.com/book" target="_blank"
|
| 153 |
+
style="background:#2e7d32;color:#fff;padding:10px 16px;border-radius:8px;text-decoration:none;font-weight:600;">
|
| 154 |
احجز استشارة طبية
|
| 155 |
</a>
|
| 156 |
</div>"""
|
|
|
|
| 158 |
level, color, desc = "🟢 طبيعية", "#2e7d32", "المشية ضمن النطاق السليم."
|
| 159 |
booking = ""
|
| 160 |
|
|
|
|
| 161 |
if red_flags >= 3 and base_ratio > 0.25:
|
| 162 |
condition = "قدم شاركوت (Charcot Foot)"
|
| 163 |
elif min(avg_Lc, avg_Rc) < 4 or low_ratio_L > 0.4 or low_ratio_R > 0.4:
|
|
|
|
| 174 |
<div>📊 درجة الخطورة: <b>{score:.1f}/10</b></div>
|
| 175 |
<div>{desc}</div>
|
| 176 |
{booking}
|
| 177 |
+
<div style='font-size:13px;color:#555;margin-top:8px;direction:rtl;text-align:right'>⚠️ التحليل يعتمد على مؤشرات متعددة ولا يُغني عن الفحص الطبي.</div>
|
| 178 |
"""
|
| 179 |
return html, _gauge_html(norm_score)
|
| 180 |
|
|
|
|
| 193 |
</div>
|
| 194 |
"""
|
| 195 |
|
| 196 |
+
# واجهة Gradio
|
| 197 |
+
with gr.Blocks(title="تحليل المشية العصبية - v8.2 (واجهة خضراء)") as demo:
|
| 198 |
+
gr.Markdown("<h2 style='direction:rtl;text-align:right'>🩺 نظام تحليل المشية العصبية – الإصدار 8.2</h2>")
|
| 199 |
gr.HTML(instructions)
|
| 200 |
with gr.Row():
|
| 201 |
with gr.Column(scale=1):
|
| 202 |
video_in = gr.File(label="📂 اختر فيديو المشي", file_types=[".mp4", ".avi", ".mov"], type="binary")
|
| 203 |
+
analyze_btn = gr.Button("🔍 بدء التحليل", elem_id="analyze_btn")
|
| 204 |
with gr.Column(scale=1):
|
| 205 |
gauge = gr.HTML("<div></div>")
|
| 206 |
out_html = gr.HTML("<i style='direction:rtl;text-align:right'>النتيجة ستظهر هنا بعد التحليل...</i>")
|
| 207 |
analyze_btn.click(fn=analyze_gait, inputs=[video_in], outputs=[out_html, gauge])
|
| 208 |
|
| 209 |
+
# تنسيق CSS موحد للأزرار باللون الأخضر
|
| 210 |
+
demo.load(None, None, None, _js="""
|
| 211 |
+
document.querySelectorAll('button, .btn').forEach(btn => {
|
| 212 |
+
btn.style.backgroundColor = '#2e7d32';
|
| 213 |
+
btn.style.color = 'white';
|
| 214 |
+
btn.style.borderRadius = '8px';
|
| 215 |
+
btn.style.fontWeight = '600';
|
| 216 |
+
});
|
| 217 |
+
""")
|
| 218 |
+
|
| 219 |
if __name__ == "__main__":
|
| 220 |
demo.launch()
|
| 221 |
|