Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -15,7 +15,7 @@ if os.path.exists(model_path):
|
|
| 15 |
model = tf.keras.models.load_model(model_path)
|
| 16 |
print("✅ تم تحميل النموذج المحفوظ.")
|
| 17 |
else:
|
| 18 |
-
print("⚠️ بناء نموذج جديد
|
| 19 |
model = models.Sequential([
|
| 20 |
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
|
| 21 |
layers.MaxPooling2D((2, 2)),
|
|
@@ -43,59 +43,58 @@ else:
|
|
| 43 |
test_images = test_images.reshape((10000, 28, 28, 1)).astype('float32') / 255
|
| 44 |
|
| 45 |
# ============================================
|
| 46 |
-
# 3. دالة
|
| 47 |
# ============================================
|
| 48 |
@spaces.GPU
|
| 49 |
def predict_sketch(image):
|
| 50 |
try:
|
| 51 |
-
#
|
| 52 |
if isinstance(image, dict):
|
| 53 |
image = image['composite']
|
| 54 |
|
| 55 |
-
#
|
| 56 |
if len(image.shape) == 3:
|
| 57 |
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
|
| 58 |
else:
|
| 59 |
gray = image
|
| 60 |
|
| 61 |
-
#
|
| 62 |
resized = cv2.resize(gray, (28, 28))
|
| 63 |
|
| 64 |
-
#
|
| 65 |
-
# حساب متوسط السطوع
|
| 66 |
mean_val = np.mean(resized)
|
| 67 |
-
|
| 68 |
-
# إذا كان المتوسط > 127 (أي الخلفية فاتحة والكتابة غامقة) → نقلب الألوان
|
| 69 |
-
# لأن MNIST تريد خلفية سوداء (0) وكتابة بيضاء (1)
|
| 70 |
if mean_val > 127:
|
|
|
|
| 71 |
resized = 255 - resized
|
|
|
|
|
|
|
|
|
|
| 72 |
|
| 73 |
-
#
|
| 74 |
_, thresh = cv2.threshold(resized, 128, 255, cv2.THRESH_BINARY)
|
| 75 |
|
| 76 |
-
#
|
| 77 |
normalized = thresh.astype('float32') / 255.0
|
| 78 |
reshaped = normalized.reshape(1, 28, 28, 1)
|
| 79 |
|
| 80 |
-
#
|
| 81 |
pred = model.predict(reshaped, verbose=0)[0]
|
| 82 |
-
predicted_class = np.argmax(pred)
|
| 83 |
-
confidence = np.max(pred)
|
| 84 |
|
| 85 |
-
#
|
| 86 |
-
debug_info = f"""
|
| 87 |
-
📊 معلومات المعالجة:
|
| 88 |
-
- متوسط السطوع الأصلي: {mean_val:.1f}
|
| 89 |
-
- تم {'قلب الألوان' if mean_val > 127 else 'الإبقاء على الألوان'}
|
| 90 |
-
- الفئة المتوقعة: {predicted_class}
|
| 91 |
-
- نسبة الثقة: {confidence:.2%}
|
| 92 |
-
- أعلى 3 احتمالات:
|
| 93 |
-
"""
|
| 94 |
top3_idx = np.argsort(pred)[-3:][::-1]
|
| 95 |
-
for i, idx in enumerate(top3_idx)
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
return {str(i): float(pred[i]) for i in range(10)}, debug_info
|
| 100 |
|
| 101 |
except Exception as e:
|
|
@@ -107,13 +106,13 @@ def predict_sketch(image):
|
|
| 107 |
def random_example():
|
| 108 |
idx = np.random.randint(0, len(test_images))
|
| 109 |
img = test_images[idx].reshape(28, 28)
|
| 110 |
-
# تكبير الصورة ل
|
| 111 |
img_large = cv2.resize(img, (280, 280))
|
| 112 |
img_rgb = np.stack([img_large] * 3, axis=2)
|
| 113 |
return img_rgb, f"الرقم الحقيقي: {test_labels[idx]}"
|
| 114 |
|
| 115 |
# ============================================
|
| 116 |
-
# 5. بناء واجهة Gradio
|
| 117 |
# ============================================
|
| 118 |
with gr.Blocks(title="MNIST Recognizer") as demo:
|
| 119 |
gr.Markdown("# 🧠 التعرف على الأرقام المكتوبة بخط اليد")
|
|
@@ -121,15 +120,12 @@ with gr.Blocks(title="MNIST Recognizer") as demo:
|
|
| 121 |
|
| 122 |
with gr.Row():
|
| 123 |
with gr.Column(scale=1):
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
brush_radius=12, # تحكم في سمك الفرشاة
|
| 127 |
-
brush_color="#FFFFFF" # لون الفرشاة (أبيض على خلفية سوداء)
|
| 128 |
-
)
|
| 129 |
with gr.Row():
|
| 130 |
submit_btn = gr.Button("🔮 توقع", variant="primary")
|
| 131 |
random_btn = gr.Button("🎲 مثال عشوائي", variant="secondary")
|
| 132 |
-
info = gr.Textbox(label="📌 معلومات التصحيح", interactive=False, lines=
|
| 133 |
|
| 134 |
with gr.Column(scale=1):
|
| 135 |
output = gr.Label(num_top_classes=3, label="📊 الاحتمالات")
|
|
@@ -138,6 +134,6 @@ with gr.Blocks(title="MNIST Recognizer") as demo:
|
|
| 138 |
random_btn.click(fn=random_example, inputs=[], outputs=[sketch, info])
|
| 139 |
|
| 140 |
# ============================================
|
| 141 |
-
# 6. تشغيل التطبيق (في النطاق العام)
|
| 142 |
# ============================================
|
| 143 |
demo.launch()
|
|
|
|
| 15 |
model = tf.keras.models.load_model(model_path)
|
| 16 |
print("✅ تم تحميل النموذج المحفوظ.")
|
| 17 |
else:
|
| 18 |
+
print("⚠️ بناء نموذج جديد...")
|
| 19 |
model = models.Sequential([
|
| 20 |
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
|
| 21 |
layers.MaxPooling2D((2, 2)),
|
|
|
|
| 43 |
test_images = test_images.reshape((10000, 28, 28, 1)).astype('float32') / 255
|
| 44 |
|
| 45 |
# ============================================
|
| 46 |
+
# 3. دالة التنبؤ (ذكية وتظهر معلومات التصحيح)
|
| 47 |
# ============================================
|
| 48 |
@spaces.GPU
|
| 49 |
def predict_sketch(image):
|
| 50 |
try:
|
| 51 |
+
# 3.1 التأكد من أن الصورة بصيغة numpy
|
| 52 |
if isinstance(image, dict):
|
| 53 |
image = image['composite']
|
| 54 |
|
| 55 |
+
# 3.2 تحويل إلى تدرج رمادي
|
| 56 |
if len(image.shape) == 3:
|
| 57 |
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
|
| 58 |
else:
|
| 59 |
gray = image
|
| 60 |
|
| 61 |
+
# 3.3 تغيير الحجم إلى 28x28
|
| 62 |
resized = cv2.resize(gray, (28, 28))
|
| 63 |
|
| 64 |
+
# 3.4 اكتشاف اتجاه الألوان تلقائياً
|
|
|
|
| 65 |
mean_val = np.mean(resized)
|
|
|
|
|
|
|
|
|
|
| 66 |
if mean_val > 127:
|
| 67 |
+
# الخلفية فاتحة، نقلب الألوان
|
| 68 |
resized = 255 - resized
|
| 69 |
+
flip_status = "تم قلب الألوان (خلفية فاتحة → خلفية سوداء)"
|
| 70 |
+
else:
|
| 71 |
+
flip_status = "الإبقاء على الألوان (خلفية سوداء بالفعل)"
|
| 72 |
|
| 73 |
+
# 3.5 تطبيق عتبة لتحسين الرسم
|
| 74 |
_, thresh = cv2.threshold(resized, 128, 255, cv2.THRESH_BINARY)
|
| 75 |
|
| 76 |
+
# 3.6 تطبيع وإعادة تشكيل
|
| 77 |
normalized = thresh.astype('float32') / 255.0
|
| 78 |
reshaped = normalized.reshape(1, 28, 28, 1)
|
| 79 |
|
| 80 |
+
# 3.7 التنبؤ
|
| 81 |
pred = model.predict(reshaped, verbose=0)[0]
|
| 82 |
+
predicted_class = int(np.argmax(pred))
|
| 83 |
+
confidence = float(np.max(pred))
|
| 84 |
|
| 85 |
+
# 3.8 بناء معلومات التصحيح
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
top3_idx = np.argsort(pred)[-3:][::-1]
|
| 87 |
+
top3_str = "\n".join([f" {i+1}. {idx}: {pred[idx]:.2%}" for i, idx in enumerate(top3_idx)])
|
| 88 |
+
debug_info = f"""
|
| 89 |
+
📊 معلومات المعالجة:
|
| 90 |
+
- متوسط السطوع الأصلي: {mean_val:.1f}
|
| 91 |
+
- {flip_status}
|
| 92 |
+
- الفئة المتوقعة: {predicted_class}
|
| 93 |
+
- نسبة الثقة: {confidence:.2%}
|
| 94 |
+
- أعلى 3 احتمالات:
|
| 95 |
+
{top3_str}
|
| 96 |
+
"""
|
| 97 |
+
# 3.9 إرجاع الاحتمالات ومعلومات التصحيح
|
| 98 |
return {str(i): float(pred[i]) for i in range(10)}, debug_info
|
| 99 |
|
| 100 |
except Exception as e:
|
|
|
|
| 106 |
def random_example():
|
| 107 |
idx = np.random.randint(0, len(test_images))
|
| 108 |
img = test_images[idx].reshape(28, 28)
|
| 109 |
+
# تكبير الصورة لـ Sketchpad
|
| 110 |
img_large = cv2.resize(img, (280, 280))
|
| 111 |
img_rgb = np.stack([img_large] * 3, axis=2)
|
| 112 |
return img_rgb, f"الرقم الحقيقي: {test_labels[idx]}"
|
| 113 |
|
| 114 |
# ============================================
|
| 115 |
+
# 5. بناء واجهة Gradio (بدون وسائط غير مدعومة)
|
| 116 |
# ============================================
|
| 117 |
with gr.Blocks(title="MNIST Recognizer") as demo:
|
| 118 |
gr.Markdown("# 🧠 التعرف على الأرقام المكتوبة بخط اليد")
|
|
|
|
| 120 |
|
| 121 |
with gr.Row():
|
| 122 |
with gr.Column(scale=1):
|
| 123 |
+
# 🔥 حذف brush_radius و brush_color نهائياً
|
| 124 |
+
sketch = gr.Sketchpad(label="✏️ ارسم هنا")
|
|
|
|
|
|
|
|
|
|
| 125 |
with gr.Row():
|
| 126 |
submit_btn = gr.Button("🔮 توقع", variant="primary")
|
| 127 |
random_btn = gr.Button("🎲 مثال عشوائي", variant="secondary")
|
| 128 |
+
info = gr.Textbox(label="📌 معلومات التصحيح", interactive=False, lines=10)
|
| 129 |
|
| 130 |
with gr.Column(scale=1):
|
| 131 |
output = gr.Label(num_top_classes=3, label="📊 الاحتمالات")
|
|
|
|
| 134 |
random_btn.click(fn=random_example, inputs=[], outputs=[sketch, info])
|
| 135 |
|
| 136 |
# ============================================
|
| 137 |
+
# 6. تشغيل التطبيق (في النطاق العام لـ ZeroGPU)
|
| 138 |
# ============================================
|
| 139 |
demo.launch()
|