EngReem85 commited on
Commit
d6c8026
·
verified ·
1 Parent(s): d819264

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -27
app.py CHANGED
@@ -1,20 +1,72 @@
 
1
  import cv2
2
  import gradio as gr
3
  import numpy as np
4
  import tensorflow as tf
5
  from scipy import ndimage
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
- # 1. تحميل النموذج المحفوظ مباشرة
8
- MODEL_PATH = "mnist_advanced_model.keras"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- try:
11
- model = tf.keras.models.load_model(MODEL_PATH)
12
- print("✅ تم تحميل النموذج بنجاح")
13
- except Exception as e:
14
- print(f"❌ خطأ: لم يتم العثور على ملف النموذج '{MODEL_PATH}'. التأكد من وجود الملف بجانب app.py")
15
 
16
 
17
- # 2. دالة تمركز الصورة
 
 
 
 
18
  def center_image(img):
19
  cy, cx = ndimage.center_of_mass(img)
20
  rows, cols = img.shape
@@ -24,63 +76,57 @@ def center_image(img):
24
  return cv2.warpAffine(img, M, (cols, rows))
25
 
26
 
27
- # 3. دالة التنبؤ
28
  def predict(image):
29
  if image is None:
30
  return None, {"error": "لم يتم الرسم"}
31
 
32
- # استخراج الصورة إذا كانت الواجهة تُرجع قاموساً (Gradio 4+)
33
  if isinstance(image, dict):
34
  image = image.get("composite", image.get("background"))
35
 
36
- # تحويل الصورة إلى رمادي وعكس الألوان (أبيض على أسود)
37
  gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
38
  _, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
39
 
40
- # اقتصاص الجزء المرسوم وتغيير حجمه
41
  coords = cv2.findNonZero(thresh)
42
  if coords is not None:
43
  x, y, w, h = cv2.boundingRect(coords)
44
  cropped = thresh[y : y + h, x : x + w]
45
 
46
- # الحفاظ على أبعاد الرسمة عند التحجيم لـ 20x20
47
  if w > h:
48
  new_w, new_h = 20, int(h * (20 / w))
49
  else:
50
  new_h, new_w = 20, int(w * (20 / h))
51
 
52
- resized = cv2.resize(cropped, (new_w, new_h), interpolation=cv2.INTER_AREA)
53
-
54
- # إضافة إطار (Padding) لتصبح الصورة 28x28
55
- pad_vert = (28 - new_h) // 2
56
- pad_horiz = (28 - new_w) // 2
 
57
  padded = np.pad(
58
  resized,
59
- ((pad_vert, 28 - new_h - pad_vert), (pad_horiz, 28 - new_w - pad_horiz)),
60
  "constant",
61
  )
62
  else:
63
  padded = cv2.resize(thresh, (28, 28))
64
 
65
- # تمركز كتلة الرسمة
66
  final_img = center_image(padded)
67
-
68
- # تجهيز الصورة والتنبؤ
69
  input_data = (final_img.astype("float32") / 255.0).reshape(1, 28, 28, 1)
70
- pred = model.predict(input_data, verbose=0)[0]
71
 
 
72
  return final_img, {str(i): float(pred[i]) for i in range(10)}
73
 
74
 
75
- # 4. واجهة Gradio
76
  with gr.Blocks(title="MNIST Predictor") as demo:
77
- gr.Markdown("# 🧠 التنبؤ بالأرقام المرسومة")
78
-
79
  with gr.Row():
80
  with gr.Column():
81
  input_pad = gr.Sketchpad(label="ارسم رقماً هنا")
82
  btn_predict = gr.Button("تنبؤ", variant="primary")
83
-
84
  with gr.Column():
85
  out_label = gr.Label(num_top_classes=3, label="النتيجة")
86
  out_img = gr.Image(label="الصورة المعالجة (28x28)", image_mode="L")
 
1
+ import os
2
  import cv2
3
  import gradio as gr
4
  import numpy as np
5
  import tensorflow as tf
6
  from scipy import ndimage
7
+ from tensorflow.keras import layers, models
8
+
9
+ MODEL_PATH = "mnist_model.keras"
10
+
11
+
12
+ def get_or_build_model():
13
+ # 1. إذا كان النموذج موجوداً، قم بتحميله فوراً
14
+ if os.path.exists(MODEL_PATH):
15
+ print("✅ تم تحميل النموذج بنجاح من الملف")
16
+ return tf.keras.models.load_model(MODEL_PATH)
17
+
18
+ # 2. إذا لم يكن موجوداً، يتم بناؤه وتدريبه سريعاً لمرة واحدة
19
+ print("⚠️ لم يتم العثور على ملف النموذج. جاري بناء وتدريب نموذج جديد على CPU...")
20
+ model = models.Sequential(
21
+ [
22
+ layers.Input(shape=(28, 28, 1)),
23
+ layers.Conv2D(32, (3, 3), activation="relu"),
24
+ layers.BatchNormalization(),
25
+ layers.MaxPooling2D((2, 2)),
26
+ layers.Conv2D(64, (3, 3), activation="relu"),
27
+ layers.BatchNormalization(),
28
+ layers.MaxPooling2D((2, 2)),
29
+ layers.Flatten(),
30
+ layers.Dense(64, activation="relu"),
31
+ layers.Dropout(0.3),
32
+ layers.Dense(10, activation="softmax"),
33
+ ]
34
+ )
35
+
36
+ model.compile(
37
+ optimizer="adam",
38
+ loss="sparse_categorical_crossentropy",
39
+ metrics=["accuracy"],
40
+ )
41
 
42
+ # تحميل البيانات وتقسيمها يدوياً لتفادي أخطاء Keras 3
43
+ (x_train_full, y_train_full), _ = tf.keras.datasets.mnist.load_data()
44
+ x_train_full = x_train_full.reshape(-1, 28, 28, 1).astype("float32") / 255.0
45
+
46
+ split = int(len(x_train_full) * 0.9)
47
+ x_tr, x_va = x_train_full[:split], x_train_full[split:]
48
+ y_tr, y_va = y_train_full[:split], y_train_full[split:]
49
+
50
+ # تدريب خفيف جداً لـ 3 جولات فقط (سريع ومناسب لـ CPU Space)
51
+ model.fit(
52
+ x_tr,
53
+ y_tr,
54
+ epochs=3,
55
+ batch_size=128,
56
+ validation_data=(x_va, y_va),
57
+ verbose=1,
58
+ )
59
 
60
+ model.save(MODEL_PATH)
61
+ print("✅ تم تدريب النموذج وحفظه بنجاح")
62
+ return model
 
 
63
 
64
 
65
+ # تحميل أو بناء النموذج
66
+ model = get_or_build_model()
67
+
68
+
69
+ # دالة تمركز كتلة الرسم
70
  def center_image(img):
71
  cy, cx = ndimage.center_of_mass(img)
72
  rows, cols = img.shape
 
76
  return cv2.warpAffine(img, M, (cols, rows))
77
 
78
 
79
+ # دالة التنبؤ
80
  def predict(image):
81
  if image is None:
82
  return None, {"error": "لم يتم الرسم"}
83
 
 
84
  if isinstance(image, dict):
85
  image = image.get("composite", image.get("background"))
86
 
 
87
  gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
88
  _, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
89
 
 
90
  coords = cv2.findNonZero(thresh)
91
  if coords is not None:
92
  x, y, w, h = cv2.boundingRect(coords)
93
  cropped = thresh[y : y + h, x : x + w]
94
 
 
95
  if w > h:
96
  new_w, new_h = 20, int(h * (20 / w))
97
  else:
98
  new_h, new_w = 20, int(w * (20 / h))
99
 
100
+ resized = cv2.resize(
101
+ cropped, (new_w, new_h), interpolation=cv2.INTER_AREA
102
+ )
103
+
104
+ pad_v = (28 - new_h) // 2
105
+ pad_h = (28 - new_w) // 2
106
  padded = np.pad(
107
  resized,
108
+ ((pad_v, 28 - new_h - pad_v), (pad_h, 28 - new_w - pad_h)),
109
  "constant",
110
  )
111
  else:
112
  padded = cv2.resize(thresh, (28, 28))
113
 
 
114
  final_img = center_image(padded)
 
 
115
  input_data = (final_img.astype("float32") / 255.0).reshape(1, 28, 28, 1)
 
116
 
117
+ pred = model.predict(input_data, verbose=0)[0]
118
  return final_img, {str(i): float(pred[i]) for i in range(10)}
119
 
120
 
121
+ # واجهة Gradio
122
  with gr.Blocks(title="MNIST Predictor") as demo:
123
+ gr.Markdown("# 🧠 التنبؤ بالأرقام المرسومة (MNIST)")
124
+
125
  with gr.Row():
126
  with gr.Column():
127
  input_pad = gr.Sketchpad(label="ارسم رقماً هنا")
128
  btn_predict = gr.Button("تنبؤ", variant="primary")
129
+
130
  with gr.Column():
131
  out_label = gr.Label(num_top_classes=3, label="النتيجة")
132
  out_img = gr.Image(label="الصورة المعالجة (28x28)", image_mode="L")