Upload 3 files
Browse files- app2.py +92 -0
- best.pt +3 -0
- requirements.txt +5 -0
app2.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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()
|
best.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:bacad1fd22999b106284f1aace0db464287ed72e6e9fad646696d1a1945030f0
|
| 3 |
+
size 6422616
|
requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
flask==3.0.0
|
| 2 |
+
opencv-python==4.8.1.78
|
| 3 |
+
numpy==2.1.2
|
| 4 |
+
ultralytics==8.0.196
|
| 5 |
+
Pillow==10.1.0
|