Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -14,13 +14,13 @@ DESCRIPTION = """
|
|
| 14 |
|
| 15 |
✨ امکانات:
|
| 16 |
- تشخیص چهرههای یکسان از زوایای مختلف
|
| 17 |
-
- مقاوم در برابر تغییرات نور و آرایش
|
| 18 |
- دقت بالا در شرایط مختلف
|
| 19 |
- نمایش نتایج کامل و تحلیلی
|
| 20 |
|
| 21 |
📌 راهنمایی:
|
| 22 |
1. تصویر اول را آپلود کنید
|
| 23 |
-
2. تصویر دوم را آپلود کنید
|
| 24 |
3. دقت مورد نظر را انتخاب کنید
|
| 25 |
4. روی دکمه "تشخیص هویت" کلیک کنید
|
| 26 |
"""
|
|
@@ -29,35 +29,12 @@ DESCRIPTION = """
|
|
| 29 |
ARTICLE = """
|
| 30 |
### 🔬 نحوه عملکرد سیستم
|
| 31 |
|
| 32 |
-
این سیستم از الگوریتمهای پیشرفته یادگیری
|
| 33 |
|
| 34 |
1. **تشخیص چهره**: پیدا کردن موقعیت چهره در تصویر
|
| 35 |
-
2. **استخراج ویژگی**: تبدیل چهره به بردار عددی
|
| 36 |
3. **مقایسه**: محاسبه فاصله بین بردارهای ویژگی
|
| 37 |
4. **تصمیمگیری**: مقایسه فاصله با آستانه انتخابی
|
| 38 |
-
|
| 39 |
-
### 🎯 تنظیمات دقت
|
| 40 |
-
|
| 41 |
-
- **دقت بالا** (آستانه ۰.۴): فقط چهرههای کاملاً مشابه را تشخیص میدهد
|
| 42 |
-
- **دقت متوسط** (آستانه ۰.۶): بهترین تعادل بین دقت و انعطاف
|
| 43 |
-
- **دقت پایین** (آستانه ۰.۸): چهرههای با تفاوتهای بیشتر را هم تشخیص میدهد
|
| 44 |
-
|
| 45 |
-
### 📊 جدول راهنمای نتایج
|
| 46 |
-
|
| 47 |
-
| فاصله | نتیجه | اطمینان |
|
| 48 |
-
|-------|-------|---------|
|
| 49 |
-
| ۰.۰۰ - ۰.۴۰ | یکسان ✓ | بسیار بالا |
|
| 50 |
-
| ۰.۴۰ - ۰.۵۵ | یکسان ✓ | بالا |
|
| 51 |
-
| ۰.۵۵ - ۰.۶۵ | یکسان ✓ | متوسط |
|
| 52 |
-
| ۰.۶۵ - ۰.۸۰ | متفاوت ✗ | متوسط |
|
| 53 |
-
| ۰.۸۰ به بالا | متفاوت ✗ | بالا |
|
| 54 |
-
|
| 55 |
-
### ⚠️ نکات مهم
|
| 56 |
-
|
| 57 |
-
- تصاویر باید حداقل ۱۰۰x100 پیکسل باشند
|
| 58 |
-
- چهره باید کامل در تصویر باشد
|
| 59 |
-
- بهترین نتیجه برای تصاویر روبرو
|
| 60 |
-
- در صورت عدم تشخیص، تصویر را دوباره آپلود کنید
|
| 61 |
"""
|
| 62 |
|
| 63 |
# تابع تشخیص چهره با OpenCV
|
|
@@ -109,7 +86,7 @@ def extract_face_features(image_array, faces):
|
|
| 109 |
# نرمالسازی
|
| 110 |
face_normalized = face_resized / 255.0
|
| 111 |
|
| 112 |
-
# استخراج ویژگیهای ساده
|
| 113 |
features = {
|
| 114 |
'histogram': cv2.calcHist([face_resized], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256]).flatten(),
|
| 115 |
'mean_color': face_normalized.mean(axis=(0, 1)),
|
|
@@ -118,9 +95,9 @@ def extract_face_features(image_array, faces):
|
|
| 118 |
|
| 119 |
# ترکیب ویژگیها
|
| 120 |
feature_vector = np.concatenate([
|
| 121 |
-
features['histogram'][:64],
|
| 122 |
-
features['mean_color'] * 10,
|
| 123 |
-
features['std_color'] * 10,
|
| 124 |
])
|
| 125 |
|
| 126 |
return feature_vector
|
|
@@ -147,6 +124,9 @@ def compare_features(features1, features2):
|
|
| 147 |
def process_faces(image1, image2, precision_level):
|
| 148 |
"""پردازش و مقایسه دو تصویر چهره"""
|
| 149 |
|
|
|
|
|
|
|
|
|
|
| 150 |
# تبدیل تصاویر به آرایه
|
| 151 |
if isinstance(image1, str):
|
| 152 |
image1_array = np.array(Image.open(image1))
|
|
@@ -158,53 +138,58 @@ def process_faces(image1, image2, precision_level):
|
|
| 158 |
else:
|
| 159 |
image2_array = np.array(image2)
|
| 160 |
|
| 161 |
-
# تنظیم آستانه بر اساس انتخاب کاربر
|
| 162 |
thresholds = {
|
| 163 |
'high': 25.0, # دقت بالا
|
| 164 |
'medium': 30.0, # دقت متوسط
|
| 165 |
'low': 35.0 # دقت پایین
|
| 166 |
}
|
| 167 |
-
|
|
|
|
|
|
|
| 168 |
|
| 169 |
# تشخیص چهره در تصویر اول
|
| 170 |
faces1 = detect_faces_opencv(image1_array)
|
| 171 |
if len(faces1) == 0:
|
| 172 |
-
return "❌ خطا: هیچ چهرهای در تصویر اول یافت نشد!",
|
| 173 |
|
| 174 |
# تشخیص چهره در تصویر دوم
|
| 175 |
faces2 = detect_faces_opencv(image2_array)
|
| 176 |
if len(faces2) == 0:
|
| 177 |
-
return "❌ خطا: هیچ چهرهای در تصویر دوم یافت نشد!",
|
| 178 |
|
| 179 |
# استخراج ویژگیها
|
| 180 |
features1 = extract_face_features(image1_array, faces1)
|
| 181 |
features2 = extract_face_features(image2_array, faces2)
|
| 182 |
|
| 183 |
if features1 is None:
|
| 184 |
-
return "❌ خطا: استخراج ویژگیهای چهره اول ناموفق!",
|
| 185 |
|
| 186 |
if features2 is None:
|
| 187 |
-
return "❌ خطا: استخراج ویژگیهای چهره دوم ناموفق!",
|
| 188 |
|
| 189 |
# مقایسه ویژگیها
|
| 190 |
distance, similarity = compare_features(features1, features2)
|
| 191 |
|
| 192 |
if distance is None or similarity is None:
|
| 193 |
-
return "❌ خطا در مقایسه ویژگیها!",
|
| 194 |
|
| 195 |
# تصمیمگیری
|
| 196 |
is_match = distance <= threshold
|
| 197 |
|
| 198 |
-
# ایجاد تصاویر با مستطیل دور چهره
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
|
|
|
|
|
|
|
|
|
| 208 |
|
| 209 |
# ایجاد گزارش نتایج
|
| 210 |
result_text = f"""
|
|
@@ -212,7 +197,7 @@ def process_faces(image1, image2, precision_level):
|
|
| 212 |
|
| 213 |
📊 **آمار فنی:**
|
| 214 |
- فاصله بردار ویژگی: `{distance:.2f}`
|
| 215 |
-
- میزان شباهت: `{similarity:.4f}`
|
| 216 |
- آستانه انتخابی: `{threshold:.2f}`
|
| 217 |
|
| 218 |
🎭 **نتیجهگیری:**
|
|
@@ -248,16 +233,14 @@ def process_faces(image1, image2, precision_level):
|
|
| 248 |
result_text += f"""
|
| 249 |
|
| 250 |
📈 **راهنمای تفسیر نتایج:**
|
| 251 |
-
- فاصله ۰-۲۰: شباهت بسیار زیاد
|
| 252 |
-
- فاصله ۲۰-۲۵: شباهت زیاد
|
| 253 |
-
- فاصله ۲۵-۳۰: شباهت متوسط
|
| 254 |
-
- فاصله ۳۰-۴۰: تفاوت متوسط
|
| 255 |
-
- فاصله +۴۰: تفاوت زیاد
|
| 256 |
-
|
| 257 |
-
⚠️ **توجه:** این نتایج بر اساس الگوریتمهای یادگیری ماشین است و احتمال خطای بسیار کمی دارد.
|
| 258 |
"""
|
| 259 |
|
| 260 |
-
return result_text,
|
| 261 |
|
| 262 |
# ایجاد رابط Gradio
|
| 263 |
with gr.Blocks(theme=gr.themes.Soft(), title=TITLE) as demo:
|
|
@@ -284,14 +267,14 @@ with gr.Blocks(theme=gr.themes.Soft(), title=TITLE) as demo:
|
|
| 284 |
image2_input = gr.Image(label="📸 تصویر چهره دوم", type="pil", height=250)
|
| 285 |
gr.HTML("<p style='text-align: center; color: gray; font-size: 12px;'>تصویر دوم را انتخاب یا آپلود کنید</p>")
|
| 286 |
|
| 287 |
-
# بخش تنظیمات
|
| 288 |
with gr.Row():
|
| 289 |
with gr.Column():
|
| 290 |
precision_input = gr.Radio(
|
| 291 |
choices=[
|
| 292 |
-
(
|
| 293 |
-
(
|
| 294 |
-
(
|
| 295 |
],
|
| 296 |
label="🎯 سطح دقت تشخیص",
|
| 297 |
value='medium',
|
|
@@ -333,17 +316,7 @@ with gr.Blocks(theme=gr.themes.Soft(), title=TITLE) as demo:
|
|
| 333 |
outputs=[output_text, output_image1, output_image2]
|
| 334 |
)
|
| 335 |
|
| 336 |
-
#
|
| 337 |
-
gr.Examples(
|
| 338 |
-
examples=[
|
| 339 |
-
["examples/face1.jpg", "examples/face2.jpg", "medium"],
|
| 340 |
-
],
|
| 341 |
-
inputs=[image1_input, image2_input, precision_input],
|
| 342 |
-
outputs=[output_text],
|
| 343 |
-
fn=process_faces,
|
| 344 |
-
cache_examples=False,
|
| 345 |
-
label="🧪 تست با مثالهای آماده"
|
| 346 |
-
)
|
| 347 |
|
| 348 |
# اجرای برنامه
|
| 349 |
if __name__ == "__main__":
|
|
|
|
| 14 |
|
| 15 |
✨ امکانات:
|
| 16 |
- تشخیص چهرههای یکسان از زوایای مختلف
|
| 17 |
+
- مقاوم در برابر تغییرات نور و آرایش
|
| 18 |
- دقت بالا در شرایط مختلف
|
| 19 |
- نمایش نتایج کامل و تحلیلی
|
| 20 |
|
| 21 |
📌 راهنمایی:
|
| 22 |
1. تصویر اول را آپلود کنید
|
| 23 |
+
2. تصویر دوم را آپلود کنید
|
| 24 |
3. دقت مورد نظر را انتخاب کنید
|
| 25 |
4. روی دکمه "تشخیص هویت" کلیک کنید
|
| 26 |
"""
|
|
|
|
| 29 |
ARTICLE = """
|
| 30 |
### 🔬 نحوه عملکرد سیستم
|
| 31 |
|
| 32 |
+
این سیستم از الگوریتمهای پیشرفته یادگیری ماشین استفاده میکند:
|
| 33 |
|
| 34 |
1. **تشخیص چهره**: پیدا کردن موقعیت چهره در تصویر
|
| 35 |
+
2. **استخراج ویژگی**: تبدیل چهره به بردار عددی
|
| 36 |
3. **مقایسه**: محاسبه فاصله بین بردارهای ویژگی
|
| 37 |
4. **تصمیمگیری**: مقایسه فاصله با آستانه انتخابی
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
"""
|
| 39 |
|
| 40 |
# تابع تشخیص چهره با OpenCV
|
|
|
|
| 86 |
# نرمالسازی
|
| 87 |
face_normalized = face_resized / 255.0
|
| 88 |
|
| 89 |
+
# استخراج ویژگیهای ساده
|
| 90 |
features = {
|
| 91 |
'histogram': cv2.calcHist([face_resized], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256]).flatten(),
|
| 92 |
'mean_color': face_normalized.mean(axis=(0, 1)),
|
|
|
|
| 95 |
|
| 96 |
# ترکیب ویژگیها
|
| 97 |
feature_vector = np.concatenate([
|
| 98 |
+
features['histogram'][:64],
|
| 99 |
+
features['mean_color'] * 10,
|
| 100 |
+
features['std_color'] * 10,
|
| 101 |
])
|
| 102 |
|
| 103 |
return feature_vector
|
|
|
|
| 124 |
def process_faces(image1, image2, precision_level):
|
| 125 |
"""پردازش و مقایسه دو تصویر چهره"""
|
| 126 |
|
| 127 |
+
# دیباگ: چاپ مقدار دریافتی
|
| 128 |
+
print(f"🔍 precision_level دریافت شده: {precision_level} (نوع: {type(precision_level)})")
|
| 129 |
+
|
| 130 |
# تبدیل تصاویر به آرایه
|
| 131 |
if isinstance(image1, str):
|
| 132 |
image1_array = np.array(Image.open(image1))
|
|
|
|
| 138 |
else:
|
| 139 |
image2_array = np.array(image2)
|
| 140 |
|
| 141 |
+
# تنظیم آستانه بر اساس انتخاب کاربر - **تصحیح شده**
|
| 142 |
thresholds = {
|
| 143 |
'high': 25.0, # دقت بالا
|
| 144 |
'medium': 30.0, # دقت متوسط
|
| 145 |
'low': 35.0 # دقت پایین
|
| 146 |
}
|
| 147 |
+
|
| 148 |
+
threshold = thresholds.get(precision_level, 30.0) # مقدار پیشفرض
|
| 149 |
+
print(f"🔧 آستانه انتخاب شده: {threshold}")
|
| 150 |
|
| 151 |
# تشخیص چهره در تصویر اول
|
| 152 |
faces1 = detect_faces_opencv(image1_array)
|
| 153 |
if len(faces1) == 0:
|
| 154 |
+
return "❌ خطا: هیچ چهرهای در تصویر اول یافت نشد!", None, None
|
| 155 |
|
| 156 |
# تشخیص چهره در تصویر دوم
|
| 157 |
faces2 = detect_faces_opencv(image2_array)
|
| 158 |
if len(faces2) == 0:
|
| 159 |
+
return "❌ خطا: هیچ چهرهای در تصویر دوم یافت نشد!", None, None
|
| 160 |
|
| 161 |
# استخراج ویژگیها
|
| 162 |
features1 = extract_face_features(image1_array, faces1)
|
| 163 |
features2 = extract_face_features(image2_array, faces2)
|
| 164 |
|
| 165 |
if features1 is None:
|
| 166 |
+
return "❌ خطا: استخراج ویژگیهای چهره اول ناموفق!", None, None
|
| 167 |
|
| 168 |
if features2 is None:
|
| 169 |
+
return "❌ خطا: استخراج ویژگیهای چهره دوم ناموفق!", None, None
|
| 170 |
|
| 171 |
# مقایسه ویژگیها
|
| 172 |
distance, similarity = compare_features(features1, features2)
|
| 173 |
|
| 174 |
if distance is None or similarity is None:
|
| 175 |
+
return "❌ خطا در مقایسه ویژگیها!", None, None
|
| 176 |
|
| 177 |
# تصمیمگیری
|
| 178 |
is_match = distance <= threshold
|
| 179 |
|
| 180 |
+
# ایجاد تصاویر با مستطیل دور چهره - **تصحیح شده**
|
| 181 |
+
img1_with_faces = image1_array.copy()
|
| 182 |
+
img2_with_faces = image2_array.copy()
|
| 183 |
+
|
| 184 |
+
for (x, y, w, h) in faces1:
|
| 185 |
+
cv2.rectangle(img1_with_faces, (x, y), (x+w, y+h), (0, 255, 0), 3)
|
| 186 |
+
|
| 187 |
+
for (x, y, w, h) in faces2:
|
| 188 |
+
cv2.rectangle(img2_with_faces, (x, y), (x+w, y+h), (0, 255, 0), 3)
|
| 189 |
+
|
| 190 |
+
# تبدیل RGB برای نمایش در Gradio
|
| 191 |
+
img1_with_faces = cv2.cvtColor(img1_with_faces, cv2.COLOR_BGR2RGB)
|
| 192 |
+
img2_with_faces = cv2.cvtColor(img2_with_faces, cv2.COLOR_BGR2RGB)
|
| 193 |
|
| 194 |
# ایجاد گزارش نتایج
|
| 195 |
result_text = f"""
|
|
|
|
| 197 |
|
| 198 |
📊 **آمار فنی:**
|
| 199 |
- فاصله بردار ویژگی: `{distance:.2f}`
|
| 200 |
+
- میزان شباهت: `{similarity:.4f}`
|
| 201 |
- آستانه انتخابی: `{threshold:.2f}`
|
| 202 |
|
| 203 |
🎭 **نتیجهگیری:**
|
|
|
|
| 233 |
result_text += f"""
|
| 234 |
|
| 235 |
📈 **راهنمای تفسیر نتایج:**
|
| 236 |
+
- فاصله ۰-۲۰: شباهت بسیار زیاد
|
| 237 |
+
- فاصله ۲۰-۲۵: شباهت زیاد
|
| 238 |
+
- فاصله ۲۵-۳۰: شباهت متوسط
|
| 239 |
+
- فاصله ۳۰-۴۰: تفاوت متوسط
|
| 240 |
+
- فاصله +۴۰: تفاوت زیاد
|
|
|
|
|
|
|
| 241 |
"""
|
| 242 |
|
| 243 |
+
return result_text, img1_with_faces, img2_with_faces
|
| 244 |
|
| 245 |
# ایجاد رابط Gradio
|
| 246 |
with gr.Blocks(theme=gr.themes.Soft(), title=TITLE) as demo:
|
|
|
|
| 267 |
image2_input = gr.Image(label="📸 تصویر چهره دوم", type="pil", height=250)
|
| 268 |
gr.HTML("<p style='text-align: center; color: gray; font-size: 12px;'>تصویر دوم را انتخاب یا آپلود کنید</p>")
|
| 269 |
|
| 270 |
+
# بخش تنظیمات - **تصحیح شده**
|
| 271 |
with gr.Row():
|
| 272 |
with gr.Column():
|
| 273 |
precision_input = gr.Radio(
|
| 274 |
choices=[
|
| 275 |
+
("high", "🟢 دقت بالا (آستانه ۲۵)"),
|
| 276 |
+
("medium", "🟡 دقت متوسط (آستانه ۳۰)"),
|
| 277 |
+
("low", "🔴 دقت پایین (آستانه ۳۵)")
|
| 278 |
],
|
| 279 |
label="🎯 سطح دقت تشخیص",
|
| 280 |
value='medium',
|
|
|
|
| 316 |
outputs=[output_text, output_image1, output_image2]
|
| 317 |
)
|
| 318 |
|
| 319 |
+
# **حذف بخش Examples به دلیل ایجاد خطا**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
|
| 321 |
# اجرای برنامه
|
| 322 |
if __name__ == "__main__":
|