EngReem85 commited on
Commit
e8eedc1
·
verified ·
1 Parent(s): b54b5bc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +170 -119
app.py CHANGED
@@ -97,26 +97,17 @@ def initialize_models():
97
 
98
  except Exception as e:
99
  print(f"❌ خطأ أثناء تحميل نموذج التجزئة: {e}")
100
- print("🔄 استخدام وضع المحاكاة للتجزئة...")
101
  segmenter = None
102
 
103
  # =========================
104
- # ✅ إعداد المعالجة المسبقة - مبسطة
105
  # =========================
106
  def preprocess_for_segmentation(img: Image.Image):
107
- """معالجة مبسطة للصورة للتجزئة"""
108
- # تحويل إلى numpy array
109
  img_np = np.array(img)
110
-
111
- # تغيير الحجم
112
  img_resized = cv2.resize(img_np, (IMG_SIZE, IMG_SIZE))
113
-
114
- # تطبيع القيم إلى [0, 1]
115
  img_normalized = img_resized.astype(np.float32) / 255.0
116
-
117
- # تحويل إلى Tensor وإعادة الترتيب (H, W, C) -> (C, H, W)
118
  img_tensor = torch.from_numpy(img_normalized).permute(2, 0, 1).float()
119
-
120
  return img_tensor
121
 
122
  def preprocess_for_classification(img: Image.Image):
@@ -128,90 +119,156 @@ def preprocess_for_classification(img: Image.Image):
128
  return img_array
129
 
130
  # =========================
131
- # ✅ دوال التحليل المحسنة
132
  # =========================
133
- def classify_image(img: Image.Image):
134
- if classifier is None:
135
- # وضع الاختبار: دائماً نعتبر هناك قرحة لاختبار التجزئة
136
- print("🔴 وضع الاختبار: افتراض وجود قرحة")
137
- return "Abnormal(Ulcer)"
138
 
139
- try:
140
- img_t = preprocess_for_classification(img)
141
- preds = classifier.predict(img_t, verbose=0)
142
- pred_class = np.argmax(preds, axis=1)[0]
143
- result = class_names[pred_class]
144
- print(f"📊 نتيجة التصنيف: {result}")
145
- return result
146
- except Exception as e:
147
- print(f"❌ خطأ في التصنيف: {e}")
148
- return "Abnormal(Ulcer)" # في حالة الخطأ، نفترض وجود قرحة للاختبار
149
-
150
- def create_test_mask(img: Image.Image):
151
- """إنشاء قناع اختباري لمحاكاة التجزئة"""
152
- width, height = img.size
153
 
154
- # إنشاء قناع أسود
155
- mask = np.zeros((height, width), dtype=np.uint8)
156
 
157
- # إضافة بعض المناطق البيضاء (تمثل القرحة)
158
- center_x, center_y = width // 2, height // 2
 
 
 
159
 
160
- # دائرة في المنتصف
161
- cv2.circle(mask, (center_x, center_y), min(width, height) // 10, 1, -1)
 
162
 
163
- # بعض النقاط العشوائية
164
- for _ in range(5):
165
- x = np.random.randint(0, width)
166
- y = np.random.randint(0, height)
167
- radius = np.random.randint(5, 20)
168
- cv2.circle(mask, (x, y), radius, 1, -1)
169
 
170
- print(f"🎯 القناع الاختباري: {np.sum(mask)} بيكسل")
171
- return mask
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
  def segment_image(img: Image.Image):
174
- """تجزئة الصورة باستخدام النموذج المدرب أو المحاكاة"""
175
- if segmenter is None:
176
- print("🔴 استخدام القناع الاختباري")
177
- return create_test_mask(img)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
- try:
180
- print("🔄 جاري تجزئة الصورة باستخدام النموذج...")
181
-
182
- # معالجة الصورة
183
- img_tensor = preprocess_for_segmentation(img)
184
- img_tensor = img_tensor.unsqueeze(0).to(DEVICE) # إضافة batch dimension
185
-
186
- # التوقع
187
- with torch.no_grad():
188
- pr_mask = segmenter(img_tensor)
189
- pred = pr_mask.squeeze().cpu().numpy()
190
-
191
- print(f"📊 توقع النموذج - المدى: [{pred.min():.3f}, {pred.max():.3f}]")
192
-
193
- # تطبيق threshold
194
- threshold = 0.3
195
- mask_bin = (pred >= threshold).astype(np.uint8)
196
-
197
- # تغيير حجم القناع ليتطابق مع الصورة الأصلية
198
- mask_resized = cv2.resize(mask_bin, (img.width, img.height))
199
-
200
- # تنظيف القناع
201
- kernel = np.ones((3, 3), np.uint8)
202
- mask_resized = cv2.morphologyEx(mask_resized, cv2.MORPH_OPEN, kernel)
203
-
204
- ulcer_pixels = np.sum(mask_resized == 1)
205
- total_pixels = mask_resized.size
206
  ulcer_ratio = ulcer_pixels / total_pixels
207
 
208
- print(f"🔍 نتائج التجزئة: {ulcer_pixels}/{total_pixels} بيكسل ({ulcer_ratio:.4f})")
209
-
210
- return mask_resized
211
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  except Exception as e:
213
- print(f"❌ خطأ في تجزئة الصورة: {e}")
214
- return create_test_mask(img)
215
 
216
  def calculate_risk(mask):
217
  """حساب مستوى الخطورة بناءً على مساحة القرحة"""
@@ -223,10 +280,10 @@ def calculate_risk(mask):
223
 
224
  if ulcer_pixels == 0:
225
  return 0.0, "No Risk", 0
226
- elif percent <= 2:
227
  level = "Low Risk"
228
  score = 1
229
- elif percent <= 8:
230
  level = "Medium Risk"
231
  score = 3
232
  else:
@@ -252,15 +309,15 @@ def apply_mask_to_image(img: Image.Image, mask):
252
  colored_mask[mask == 1] = [255, 0, 0] # لون أحمر
253
 
254
  # دمج مع الشفافية
255
- alpha = 0.6 # زيادة الشفافية لرؤية أفضل
256
  masked = cv2.addWeighted(img_np, 1 - alpha, colored_mask, alpha, 0)
257
 
258
  # إضافة حدود حمراء حول المناطق المصابة
259
  contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
260
  for contour in contours:
261
  area = cv2.contourArea(contour)
262
- if area > 10: # فقط المناطق الكبيرة enough
263
- cv2.drawContours(masked, [contour], -1, (255, 0, 0), 3) # زيادة سمك الحدود
264
 
265
  return Image.fromarray(masked.astype('uint8'))
266
 
@@ -281,7 +338,7 @@ def analyze_images(img1, img2, img3, img4):
281
  "status": "No image uploaded",
282
  "classification": "None",
283
  "ulcer_percentage": 0.0,
284
- "risk_level": "None",
285
  "risk_score": 0
286
  }
287
  continue
@@ -294,29 +351,33 @@ def analyze_images(img1, img2, img3, img4):
294
  classification = classify_image(img)
295
  print(f"📊 تصنيف الصورة {idx+1}: {classification}")
296
 
297
- # دائماً نقوم بالتجزئة للاختبار بغض النظر عن التصنيف
298
- print("🔍 جاري تجزئة الصورة...")
299
- mask = segment_image(img)
300
-
301
- # تطبيق القناع على الصورة
302
- masked_img = apply_mask_to_image(img, mask)
303
- ulcer_percent, risk_level, risk_score = calculate_risk(mask)
304
-
305
- gallery_output.append(masked_img)
306
- json_output[image_key] = {
307
- "status": "Analyzed",
308
- "classification": classification,
309
- "ulcer_percentage": round(ulcer_percent, 2),
310
- "risk_level": risk_level,
311
- "risk_score": risk_score,
312
- "ulcer_pixels": int(np.sum(mask == 1)),
313
- "total_pixels": mask.size
314
- }
 
 
 
 
 
 
315
 
316
  except Exception as e:
317
  print(f"❌ خطأ في معالجة الصورة {idx+1}: {e}")
318
- import traceback
319
- traceback.print_exc()
320
  gallery_output.append(img)
321
  json_output[image_key] = {
322
  "status": f"Error: {str(e)}",
@@ -343,8 +404,8 @@ with gr.Blocks(title="Diabetic Foot Ulcer Analysis") as demo:
343
  **تعليمات الاستخدام:**
344
  - ارفع 4 صور (باطن القدم + وجه القدم)
345
  - المناطق **الحمراء** تشير إلى القرحة المكتشفة
346
- - **مستويات الخطورة**: منخفض (≤2%), متوسط (≤8%), مرتفع (>8%)
347
- - النظام الآن في وضع الاختبار وسيظهر مناطق حمراء اختبارية
348
  """)
349
 
350
  with gr.Row():
@@ -365,15 +426,6 @@ with gr.Blocks(title="Diabetic Foot Ulcer Analysis") as demo:
365
  label="Analysis Results"
366
  )
367
 
368
- # أمثلة للاختبار
369
- gr.Examples(
370
- examples=[
371
- # يمكنك إضافة أمثلة هنا لاحقاً
372
- ],
373
- inputs=inputs,
374
- label="Try these examples"
375
- )
376
-
377
  analyze_btn.click(
378
  fn=analyze_images,
379
  inputs=inputs,
@@ -382,7 +434,6 @@ with gr.Blocks(title="Diabetic Foot Ulcer Analysis") as demo:
382
 
383
  if __name__ == "__main__":
384
  print("🚀 Starting Gradio server...")
385
- print("🔧 النظام في وضع الاختبار - سيظهر مناطق حمراء اختبارية")
386
  demo.launch(
387
  server_name="0.0.0.0",
388
  server_port=7860,
 
97
 
98
  except Exception as e:
99
  print(f"❌ خطأ أثناء تحميل نموذج التجزئة: {e}")
 
100
  segmenter = None
101
 
102
  # =========================
103
+ # ✅ إعداد المعالجة المسبقة
104
  # =========================
105
  def preprocess_for_segmentation(img: Image.Image):
106
+ """معالجة الصورة للتجزئة"""
 
107
  img_np = np.array(img)
 
 
108
  img_resized = cv2.resize(img_np, (IMG_SIZE, IMG_SIZE))
 
 
109
  img_normalized = img_resized.astype(np.float32) / 255.0
 
 
110
  img_tensor = torch.from_numpy(img_normalized).permute(2, 0, 1).float()
 
111
  return img_tensor
112
 
113
  def preprocess_for_classification(img: Image.Image):
 
119
  return img_array
120
 
121
  # =========================
122
+ # ✅ خوارزمية ذكية للكشف عن القرحة
123
  # =========================
124
+ def smart_ulcer_detection(img: Image.Image):
125
+ """كشف ذكي للقرحة باستخدام معالجة الصور المتقدمة"""
126
+ img_np = np.array(img)
127
+ original_shape = img_np.shape
 
128
 
129
+ print("🔍 بدء الكشف الذكي عن القرحة...")
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
+ # 1. تحويل إلى مساحة لون HSV للكشف الأفضل عن الألوان
132
+ hsv = cv2.cvtColor(img_np, cv2.COLOR_RGB2HSV)
133
 
134
+ # 2. كشف اللون الأحمر (القرحة النشطة)
135
+ lower_red1 = np.array([0, 70, 50])
136
+ upper_red1 = np.array([10, 255, 255])
137
+ lower_red2 = np.array([170, 70, 50])
138
+ upper_red2 = np.array([180, 255, 255])
139
 
140
+ mask_red1 = cv2.inRange(hsv, lower_red1, upper_red1)
141
+ mask_red2 = cv2.inRange(hsv, lower_red2, upper_red2)
142
+ red_mask = cv2.bitwise_or(mask_red1, mask_red2)
143
 
144
+ # 3. كشف البني/الأسود (الأنسجة الميتة)
145
+ lower_brown = np.array([0, 30, 10])
146
+ upper_brown = np.array([20, 150, 100])
147
+ brown_mask = cv2.inRange(hsv, lower_brown, upper_brown)
 
 
148
 
149
+ # 4. كشف التغيرات في الجلد باستخدام القنوات المختلفة
150
+ lab = cv2.cvtColor(img_np, cv2.COLOR_RGB2LAB)
151
+ l_channel = lab[:,:,0]
152
+
153
+ # اكتشاف المناطق الداكنة (تغيرات في الجلد)
154
+ _, dark_mask = cv2.threshold(l_channel, 100, 255, cv2.THRESH_BINARY_INV)
155
+
156
+ # 5. دمج جميع الأقنعة
157
+ combined_mask = cv2.bitwise_or(red_mask, brown_mask)
158
+ combined_mask = cv2.bitwise_or(combined_mask, dark_mask)
159
+
160
+ # 6. تنظيف القناع
161
+ kernel = np.ones((5,5), np.uint8)
162
+ combined_mask = cv2.morphologyEx(combined_mask, cv2.MORPH_CLOSE, kernel)
163
+ combined_mask = cv2.morphologyEx(combined_mask, cv2.MORPH_OPEN, kernel)
164
+
165
+ # 7. إزالة المناطق الصغيرة جداً (ضوضاء)
166
+ contours, _ = cv2.findContours(combined_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
167
+
168
+ final_mask = np.zeros_like(combined_mask)
169
+ min_area = original_shape[0] * original_shape[1] * 0.001 # 0.1% من ��ساحة الصورة
170
+
171
+ ulcer_areas = []
172
+ for contour in contours:
173
+ area = cv2.contourArea(contour)
174
+ if area > min_area:
175
+ # التحقق من الشكل - القرحة عادة غير منتظمة الشكل
176
+ perimeter = cv2.arcLength(contour, True)
177
+ if perimeter > 0:
178
+ circularity = 4 * np.pi * area / (perimeter * perimeter)
179
+ # القرحة عادة أقل دائرية من النقاط العشوائية
180
+ if circularity < 0.8: # استبعاد الأشكال الدائرية المنتظمة
181
+ cv2.fillPoly(final_mask, [contour], 255)
182
+ ulcer_areas.append(area)
183
+
184
+ # 8. إذا لم نجد مناطق مناسبة، نبحث عن مناطق الالتهاب
185
+ if len(ulcer_areas) == 0:
186
+ print("🔍 البحث عن مناطق الالتهاب...")
187
+ # كشف المناطق ذات الاحمرار الخفيف
188
+ lower_light_red = np.array([0, 30, 30])
189
+ upper_light_red = np.array([15, 255, 255])
190
+ light_red_mask = cv2.inRange(hsv, lower_light_red, upper_light_red)
191
+
192
+ contours, _ = cv2.findContours(light_red_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
193
+ for contour in contours:
194
+ area = cv2.contourArea(contour)
195
+ if area > min_area * 2: # مساحة أكبر للالتهاب
196
+ cv2.fillPoly(final_mask, [contour], 255)
197
+ ulcer_areas.append(area)
198
+
199
+ print(f"🎯 تم اكتشاف {len(ulcer_areas)} منطقة قرحة محتملة")
200
+
201
+ return (final_mask > 0).astype(np.uint8)
202
 
203
  def segment_image(img: Image.Image):
204
+ """تجزئة الصورة باستخدام النموذج المدرب أو الكشف الذكي"""
205
+ if segmenter is not None:
206
+ try:
207
+ print("🔄 جاري تجزئة الصورة باستخدام النموذج...")
208
+
209
+ # معالجة الصورة
210
+ img_tensor = preprocess_for_segmentation(img)
211
+ img_tensor = img_tensor.unsqueeze(0).to(DEVICE)
212
+
213
+ # التوقع
214
+ with torch.no_grad():
215
+ pr_mask = segmenter(img_tensor)
216
+ pred = pr_mask.squeeze().cpu().numpy()
217
+
218
+ print(f"📊 توقع النموذج - المدى: [{pred.min():.3f}, {pred.max():.3f}]")
219
+
220
+ # تطبيق threshold
221
+ threshold = 0.3
222
+ mask_bin = (pred >= threshold).astype(np.uint8)
223
+
224
+ # تغيير حجم القناع
225
+ mask_resized = cv2.resize(mask_bin, (img.width, img.height))
226
+
227
+ # تنظيف القناع
228
+ kernel = np.ones((3, 3), np.uint8)
229
+ mask_resized = cv2.morphologyEx(mask_resized, cv2.MORPH_OPEN, kernel)
230
+
231
+ ulcer_pixels = np.sum(mask_resized == 1)
232
+
233
+ if ulcer_pixels > 0:
234
+ print(f"✅ النموذج اكتشف {ulcer_pixels} بيكسل قرحة")
235
+ return mask_resized
236
+ else:
237
+ print("❌ النموذج لم يكتشف قرحة، استخدام الكشف الذكي")
238
+ return smart_ulcer_detection(img)
239
+
240
+ except Exception as e:
241
+ print(f"❌ خطأ في تجزئة الصورة: {e}")
242
 
243
+ print("🔍 استخدام الكشف الذكي عن القرحة...")
244
+ return smart_ulcer_detection(img)
245
+
246
+ def classify_image(img: Image.Image):
247
+ """تصنيف الصورة"""
248
+ if classifier is None:
249
+ # استخدام الكشف الذكي للتصنيف
250
+ mask = smart_ulcer_detection(img)
251
+ ulcer_pixels = np.sum(mask == 1)
252
+ total_pixels = mask.size
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  ulcer_ratio = ulcer_pixels / total_pixels
254
 
255
+ print(f"🔍 التصنيف الذكي: نسبة القرحة {ulcer_ratio:.4f}")
 
 
256
 
257
+ if ulcer_ratio > 0.001: # إذا كانت النسبة أكثر من 0.1%
258
+ return "Abnormal(Ulcer)"
259
+ else:
260
+ return "Normal(Healthy skin)"
261
+
262
+ try:
263
+ img_t = preprocess_for_classification(img)
264
+ preds = classifier.predict(img_t, verbose=0)
265
+ pred_class = np.argmax(preds, axis=1)[0]
266
+ result = class_names[pred_class]
267
+ print(f"📊 نتيجة التصنيف: {result}")
268
+ return result
269
  except Exception as e:
270
+ print(f"❌ خطأ في التصنيف: {e}")
271
+ return "Abnormal(Ulcer)"
272
 
273
  def calculate_risk(mask):
274
  """حساب مستوى الخطورة بناءً على مساحة القرحة"""
 
280
 
281
  if ulcer_pixels == 0:
282
  return 0.0, "No Risk", 0
283
+ elif percent <= 1:
284
  level = "Low Risk"
285
  score = 1
286
+ elif percent <= 5:
287
  level = "Medium Risk"
288
  score = 3
289
  else:
 
309
  colored_mask[mask == 1] = [255, 0, 0] # لون أحمر
310
 
311
  # دمج مع الشفافية
312
+ alpha = 0.5
313
  masked = cv2.addWeighted(img_np, 1 - alpha, colored_mask, alpha, 0)
314
 
315
  # إضافة حدود حمراء حول المناطق المصابة
316
  contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
317
  for contour in contours:
318
  area = cv2.contourArea(contour)
319
+ if area > 50:
320
+ cv2.drawContours(masked, [contour], -1, (255, 0, 0), 2)
321
 
322
  return Image.fromarray(masked.astype('uint8'))
323
 
 
338
  "status": "No image uploaded",
339
  "classification": "None",
340
  "ulcer_percentage": 0.0,
341
+ "risk_level": "None",
342
  "risk_score": 0
343
  }
344
  continue
 
351
  classification = classify_image(img)
352
  print(f"📊 تصنيف الصورة {idx+1}: {classification}")
353
 
354
+ if classification == "Abnormal(Ulcer)":
355
+ # تجزئة الصورة
356
+ mask = segment_image(img)
357
+ masked_img = apply_mask_to_image(img, mask)
358
+ ulcer_percent, risk_level, risk_score = calculate_risk(mask)
359
+
360
+ gallery_output.append(masked_img)
361
+ json_output[image_key] = {
362
+ "status": "Analyzed",
363
+ "classification": classification,
364
+ "ulcer_percentage": round(ulcer_percent, 2),
365
+ "risk_level": risk_level,
366
+ "risk_score": risk_score,
367
+ "ulcer_pixels": int(np.sum(mask == 1))
368
+ }
369
+ else:
370
+ gallery_output.append(img)
371
+ json_output[image_key] = {
372
+ "status": "Analyzed",
373
+ "classification": classification,
374
+ "ulcer_percentage": 0.0,
375
+ "risk_level": "No Risk",
376
+ "risk_score": 0
377
+ }
378
 
379
  except Exception as e:
380
  print(f"❌ خطأ في معالجة الصورة {idx+1}: {e}")
 
 
381
  gallery_output.append(img)
382
  json_output[image_key] = {
383
  "status": f"Error: {str(e)}",
 
404
  **تعليمات الاستخدام:**
405
  - ارفع 4 صور (باطن القدم + وجه القدم)
406
  - المناطق **الحمراء** تشير إلى القرحة المكتشفة
407
+ - **مستويات الخطورة**: منخفض (≤1%), متوسط (≤5%), مرتفع (>5%)
408
+ - النظام يستخدم خوارزمية ذكية للكشف عن القرحة الحقيقية
409
  """)
410
 
411
  with gr.Row():
 
426
  label="Analysis Results"
427
  )
428
 
 
 
 
 
 
 
 
 
 
429
  analyze_btn.click(
430
  fn=analyze_images,
431
  inputs=inputs,
 
434
 
435
  if __name__ == "__main__":
436
  print("🚀 Starting Gradio server...")
 
437
  demo.launch(
438
  server_name="0.0.0.0",
439
  server_port=7860,