face1 / app.py
suprimedev's picture
Update app.py
09cb33c verified
import gradio as gr
import numpy as np
from PIL import Image
import cv2
import dlib
import os
import warnings
warnings.filterwarnings('ignore')
# عنوان برنامه
TITLE = "🔍 سامانه پیشرفته تشخیص هویت چهره"
DESCRIPTION = """
🎯 سیستم هوشمند تشخیص هویت با استفاده از نقاط کلیدی صورت
✨ امکانات:
- تشخیص ۶۸ نقطه کلیدی روی چهره
- مقایسه ساختار استخوانی و هندسی صورت
- مقاوم در برابر تغییرات نور و آرایش
- دقت بسیار بالا با الگوریتم‌های پیشرفته
📌 راهنمایی:
1. تصویر اول را آپلود کنید
2. تصویر دوم را آپلود کنید
3. دقت مورد نظر را انتخاب کنید
4. روی دکمه "تشخیص هویت" کلیک کنید
"""
# بارگذاری مدل‌های dlib
print("🔄 در حال بارگذاری مدل‌های تشخیص چهره...")
try:
# تشخیص نقاط کلیدی صورت
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
detector = dlib.get_frontal_face_detector()
face_rec_model = dlib.face_recognition_model_v1('dlib_face_recognition_resnet_model_v1.dat')
print("✅ مدل‌ها با موفقیت بارگذاری شدند!")
MODELS_LOADED = True
except Exception as e:
print(f"⚠️ مدل‌ها یافت نشدند. از روش جایگزین استفاده می‌کنیم... {e}")
MODELS_LOADED = False
# تابع تشخیص چهره و نقاط کلیدی با dlib
def detect_face_landmarks_dlib(image_array):
"""تشخیص ۶۸ نقطه کلیدی صورت با dlib"""
if not MODELS_LOADED:
return None, None, None
try:
# تشخیص چهره
faces = detector(image_array, 1)
if len(faces) == 0:
return None, None, None
# گرفتن اولین چهره
face = faces[0]
# تشخیص نقاط کلیدی
shape = predictor(image_array, face)
# استخراج بردار ویژگی چهره
face_descriptor = face_rec_model.compute_face_descriptor(image_array, shape)
face_encoding = np.array(face_descriptor)
# استخراج نقاط کلیدی
landmarks = np.array([[p.x, p.y] for p in shape.parts()])
return face, landmarks, face_encoding
except Exception as e:
print(f"خطا در تشخیص نقاط کلیدی: {e}")
return None, None, None
# تابع تشخیص چهره جایگزین با OpenCV
def detect_face_features_opencv(image_array):
"""تشخیص ویژگی‌های صورت با OpenCV پیشرفته"""
try:
# تشخیص چهره
gray = cv2.cvtColor(image_array, cv2.COLOR_RGB2GRAY)
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
if len(faces) == 0:
return None, None
# گرفتن اولین چهره
x, y, w, h = faces[0]
face_region = image_array[y:y+h, x:x+w]
# استخراج ویژگی‌های پیشرفته
# ۱. هیستوگرام گرادیان‌ها (HOG)
gray_face = cv2.cvtColor(face_region, cv2.COLOR_RGB2GRAY)
gray_face = cv2.resize(gray_face, (64, 128))
# محاسبه گرادیان
gx = cv2.Sobel(gray_face, cv2.CV_32F, 1, 0)
gy = cv2.Sobel(gray_face, cv2.CV_32F, 0, 1)
mag, ang = cv2.cartToPolar(gx, gy)
# هیستوگرام گرادیان‌های جهت‌دار
bins = np.int32(16 * ang / (2 * np.pi))
bin_cells = bins[:10, :10], bins[10:, :10], bins[:10, 10:], bins[10:, 10:]
mag_cells = mag[:10, :10], mag[10:, :10], mag[:10, 10:], mag[10:, 10:]
hists = [np.bincount(b.ravel(), m.ravel(), 16) for b, m in zip(bin_cells, mag_cells)]
hist = np.hstack(hists)
# ۲. ویژگی‌های رنگ و بافت
face_resized = cv2.resize(face_region, (64, 64))
# هیستوگرام رنگ
color_hist = cv2.calcHist([face_resized], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256]).flatten()
color_hist = color_hist[:128] # گرفتن ۱۲۸ مقدار اول
# ویژگی‌های آماری
mean_color = face_resized.mean(axis=(0, 1))
std_color = face_resized.std(axis=(0, 1))
# ۳. ویژگی‌های الگوی محلی (LBP)
lbp_features = extract_lbp_features(gray_face)[:64]
# ترکیب تمام ویژگی‌ها
features = np.concatenate([
hist / (hist.sum() + 1e-8), # نرمال‌سازی هیستوگرام
color_hist / (color_hist.sum() + 1e-8), # نرمال‌سازی هیستوگرام رنگ
mean_color / 255,
std_color / 255,
lbp_features
])
return faces[0], features
except Exception as e:
print(f"خطا در استخراج ویژگی‌های OpenCV: {e}")
return None, None
def extract_lbp_features(gray_image):
"""استخراج ویژگی‌های الگوی محلی باینری (LBP)"""
try:
# تغییر سایز به اندازه ثابت
img = cv2.resize(gray_image, (64, 64))
# محاسبه LBP
lbp = np.zeros_like(img, dtype=np.uint8)
for i in range(1, img.shape[0]-1):
for j in range(1, img.shape[1]-1):
center = img[i, j]
code = 0
code |= (img[i-1, j-1] >= center) << 7
code |= (img[i-1, j] >= center) << 6
code |= (img[i-1, j+1] >= center) << 5
code |= (img[i, j+1] >= center) << 4
code |= (img[i+1, j+1] >= center) << 3
code |= (img[i+1, j] >= center) << 2
code |= (img[i+1, j-1] >= center) << 1
code |= (img[i, j-1] >= center) << 0
lbp[i, j] = code
# هیستوگرام LBP
hist, _ = np.histogram(lbp.ravel(), bins=256, range=(0, 256))
return hist
except Exception as e:
print(f"خطا در استخراج LBP: {e}")
return np.zeros(256)
# تابع مقایسه پیشرفته
def compare_faces_advanced(features1, features2, threshold):
"""مقایسه پیشرفته دو بردار ویژگی"""
if features1 is None or features2 is None:
return None, None, "❌ خطا در استخراج ویژگی‌ها"
try:
# محاسبه فاصله اقلیدسی
distance = np.linalg.norm(features1 - features2)
# محاسبه شباهت کسینوسی
cos_similarity = np.dot(features1, features2) / (np.linalg.norm(features1) * np.linalg.norm(features2) + 1e-10)
# محاسبه شباهت کلی
similarity = 1.0 / (1.0 + distance)
# تصمیم‌گیری
is_match = distance <= threshold
return distance, similarity, is_match
except Exception as e:
print(f"خطا در مقایسه: {e}")
return None, None, None
# تابع رسم نقاط کلیدی
def draw_landmarks_on_image(image_array, landmarks, face_rect):
"""رسم نقاط کلیدی و مستطیل چهره"""
img_copy = image_array.copy()
# رسم مستطیل دور چهره
if face_rect is not None:
if hasattr(face_rect, 'left'): # dlib rectangle
cv2.rectangle(img_copy, (face_rect.left(), face_rect.top()),
(face_rect.right(), face_rect.bottom()), (0, 255, 0), 3)
else: # OpenCV rectangle
x, y, w, h = face_rect
cv2.rectangle(img_copy, (x, y), (x+w, y+h), (0, 255, 0), 3)
# رسم نقاط کلیدی
if landmarks is not None:
for i, (x, y) in enumerate(landmarks):
# رنگ‌های مختلف برای نقاط مختلف صورت
if i < 17: # خط فک
color = (255, 0, 0)
elif i < 22: # ابروی راست
color = (0, 255, 0)
elif i < 27: # ابروی چپ
color = (0, 0, 255)
elif i < 36: # بینی
color = (255, 255, 0)
elif i < 48: # چشم‌ها
color = (255, 0, 255)
else: # دهان
color = (0, 255, 255)
cv2.circle(img_copy, (int(x), int(y)), 3, color, -1)
return img_copy
# تابع اصلی پردازش
def process_faces(image1, image2, precision_level):
"""پردازش و مقایسه دو تصویر چهره"""
print(f"🔍 شروع پردازش با دقت: {precision_level}")
# تبدیل تصاویر به آرایه
if isinstance(image1, str):
image1_array = np.array(Image.open(image1))
else:
image1_array = np.array(image1)
if isinstance(image2, str):
image2_array = np.array(Image.open(image2))
else:
image2_array = np.array(image2)
# تنظیم آستانه
thresholds = {
'high': 0.4, # دقت بالا
'medium': 0.5, # دقت متوسط
'low': 0.6 # دقت پایین
}
threshold = thresholds.get(precision_level, 0.5)
print(f"🔧 آستانه انتخاب شده: {threshold}")
# پردازش تصویر اول
print("📸 پردازش تصویر اول...")
if MODELS_LOADED:
face1, landmarks1, features1 = detect_face_landmarks_dlib(image1_array)
if face1 is None:
features1 = None
else:
face1, features1 = detect_face_features_opencv(image1_array)
landmarks1 = None
# پردازش تصویر دوم
print("📸 پردازش تصویر دوم...")
if MODELS_LOADED:
face2, landmarks2, features2 = detect_face_landmarks_dlib(image2_array)
if face2 is None:
features2 = None
else:
face2, features2 = detect_face_features_opencv(image2_array)
landmarks2 = None
# بررسی خطاها
if features1 is None:
return "❌ خطا: تشخیص چهره در تصویر اول ناموفق بود!", None, None
if features2 is None:
return "❌ خطا: تشخیص چهره در تصویر دوم ناموفق بود!", None, None
# مقایسه چهره‌ها
print("🔄 در حال مقایسه چهره‌ها...")
distance, similarity, is_match = compare_faces_advanced(features1, features2, threshold)
if distance is None:
return "❌ خطا در مقایسه ویژگی‌ها!", None, None
# ایجاد تصاویر با نشانگر
img1_processed = draw_landmarks_on_image(image1_array, landmarks1, face1)
img2_processed = draw_landmarks_on_image(image2_array, landmarks2, face2)
# تبدیل به RGB
img1_processed = cv2.cvtColor(img1_processed, cv2.COLOR_BGR2RGB)
img2_processed = cv2.cvtColor(img2_processed, cv2.COLOR_BGR2RGB)
# ایجاد گزارش
result_text = f"""
🎯 **نتایج تشخیص هویت چهره**
📊 **آمار فنی:**
- فاصله بردار ویژگی: `{distance:.4f}`
- میزان شباهت: `{similarity:.4f}`
- آستانه انتخابی: `{threshold:.2f}`
🎭 **نتیجه‌گیری:**
"""
if is_match:
if distance < 0.3:
confidence = "🔒 **تطبیق با اطمینان بسیار بالا**"
elif distance < 0.4:
confidence = "✅ **تطبیق با اطمینان بالا**"
else:
confidence = "✓ **تطبیق با اطمینان متوسط**"
result_text += f"""
{confidence}
🟢 **این دو تصویر متعلق به یک شخص هستند**
_تحلیل سیستم:_
- فاصله محاسبه‌شده ({distance:.4f}) کمتر از آستانه ({threshold:.2f}) است
- ساختار صورت و ویژگی‌های کلیدی بسیار مشابه هستند
- احتمال اینکه این دو تصویر از یک شخص باشند: **{(1-distance)*100:.1f}%**
"""
else:
if distance > 0.7:
confidence = "🔒 **عدم تطبیق با اطمینان بسیار بالا**"
else:
confidence = "❌ **عدم تطبیق با اطمینان متوسط**"
result_text += f"""
{confidence}
🔴 **این دو تصویر متعلق به اشخاص مختلف هستند**
_تحلیل سیستم:_
- فاصله محاسبه‌شده ({distance:.4f}) بیشتر از آستانه ({threshold:.2f}) است
- ساختار صورت و ویژگی‌های کلیدی تفاوت قابل توجهی دارند
- شباهت: **{(1-distance)*100:.1f}%**
"""
result_text += f"""
📈 **جزئیات فنی:**
"""
if MODELS_LOADED:
result_text += "- ✅ استفاده از مدل dlib با ۶۸ نقطه کلیدی\n"
else:
result_text += "- ⚠️ استفاده از روش OpenCV (دقت کمتر)\n"
result_text += f"""
- تعداد ویژگی‌های استخراج‌شده: {len(features1)}
- روش تشخیص: نقاط کلیدی صورت + ساختار هندسی
- دامنه فاصله: ۰ (کاملاً مشابه) تا ۱ (کاملاً متفاوت)
🛠️ **توضیح فنی:**
سیستم از نقاط کلیدی صورت (چشم‌ها، بینی، دهان، فک) استفاده می‌کند
و ساختار هندسی صورت را با دقت بالا مقایسه می‌کند.
"""
return result_text, img1_processed, img2_processed
# ایجاد رابط Gradio
with gr.Blocks(theme=gr.themes.Soft(), title=TITLE) as demo:
# هدر برنامه
gr.HTML(f"""
<div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px;">
<h1 style="font-size: 32px; margin-bottom: 10px;">{TITLE}</h1>
<p style="font-size: 16px; margin: 0;">سامانه هوشمند تشخیص هویت با تحلیل نقاط کلیدی صورت</p>
</div>
""")
# توضیحات
with gr.Row():
gr.Markdown(DESCRIPTION)
# بخش ورودی‌ها
with gr.Row():
with gr.Column():
image1_input = gr.Image(label="📸 تصویر چهره اول", type="pil", height=250)
gr.HTML("<p style='text-align: center; color: gray; font-size: 12px;'>تصویر اول را انتخاب یا آپلود کنید</p>")
with gr.Column():
image2_input = gr.Image(label="📸 تصویر چهره دوم", type="pil", height=250)
gr.HTML("<p style='text-align: center; color: gray; font-size: 12px;'>تصویر دوم را انتخاب یا آپلود کنید</p>")
# بخش تنظیمات
with gr.Row():
with gr.Column():
precision_input = gr.Radio(
choices=[
("high", "🟢 دقت بالا (آستانه ۰.۴)"),
("medium", "🟡 دقت متوسط (آستانه ۰.۵)"),
("low", "🔴 دقت پایین (آستانه ۰.۶)")
],
label="🎯 سطح دقت تشخیص",
value='medium',
type='value'
)
# دکمه پردازش
with gr.Row():
submit_btn = gr.Button("🚀 شروع تشخیص پیشرفته", variant="primary", size="lg")
# بخش خروجی
with gr.Row():
with gr.Column(scale=2):
output_text = gr.Markdown(label="📊 نتایج تشخیص")
with gr.Row():
with gr.Column():
output_image1 = gr.Image(label="تصویر اول - نقاط کلیدی", type="numpy", height=250)
with gr.Column():
output_image2 = gr.Image(label="تصویر دوم - نقاط کلیدی", type="numpy", height=250)
# راهنمای رنگ‌ها
gr.HTML("""
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; border-left: 4px solid #667eea;">
<h4 style="margin-top: 0;">🎨 راهنمای رنگ نقاط کلیدی:</h4>
<ul style="margin-bottom: 0;">
<li>🔵 آبی: خط فک و چانه</li>
<li>🟢 سبز: ابروی راست</li>
<li>🔴 قرمز: ابروی چپ</li>
<li>🟡 زرد: بینی</li>
<li>🟣 بنفش: چشم‌ها</li>
<li>🟡 زرد-سبز: دهان و لب‌ها</li>
<li>🟢 مستطیل سبز: محدوده کل چهره</li>
</ul>
</div>
""")
# نکات مهم
gr.HTML("""
<div style="background: #fff3cd; padding: 15px; border-radius: 8px; border-left: 4px solid #ffc107;">
<h4 style="margin-top: 0; color: #856404;">⚠️ نکات مهم:</h4>
<ul style="margin-bottom: 0; color: #856404;">
<li>برای بهترین نتیجه، از تصاویر با کیفیت بالا و نور مناسب استفاده کنید</li>
<li>چهره باید کامل در تصویر باشد و حداقل ۲۰۰x۲۰۰ پیکسل باشد</li>
<li>این سیستم از ۶۸ نقطه کلیدی صورت برای تشخیص استفاده می‌کند</li>
<li>در صورت عدم تشخیص، تصویر را کمی بزرگ‌تر کنید</li>
</ul>
</div>
""")
# تنظیمات دکمه
submit_btn.click(
fn=process_faces,
inputs=[image1_input, image2_input, precision_input],
outputs=[output_text, output_image1, output_image2]
)
# اجرای برنامه
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=True,
show_error=True
)