تشخیص چهره با استفاده از OpenCV در پایتون

گردآوری و تالیف : شهریار شریعتی
تاریخ انتشار : 07 شهریور 1398
دسته بندی ها : پایتون

OpenCV چیست؟

می‌توان OpenCV را به عنوان معروف‌ترین کتابخانه در حوزه بینایی ماشین (Computer Vision) معرفی کرد. اصل این کتابخانه برای زبان C/C++ نوشته شده اما با گذشت زمان، اکنون استفاده از آن در زبان برنامه‌نویسی پایتون نیز مقدور می‌باشد.

OpenCV برای یافتن چهره اشخاص در تصاویر مختلف، از الگوریتم‌های یادگیری ماشین استفاده می‌کند. به این دلیل که ساختار چهره بسیار پیچیده است و هیچ مثالی وجود ندارد که به وضوح، یافت شدن یا نشدن چهره در یک تصویر را اطلاع دهد. الگوریتم‌های بکار گرفته شده قادر هستند تا عملیات پیچیده تشخیص چهره را به هزاران عمل کوچک‌تر و باینری تقسیم کنند؛ سپس حل هر یک از این اعمال کوچک، بسیار ساده‌تر می‌شود. این اعمال کوچک را طبقه‌بندی‌‌‌ها یا Classifiers می‌گویند.

برای یک شیء مانند چهره، ممکن است شما 6000 یا تعداد بیشتری از طبقه‌بندی‌ها داشته باشید که هرکدام از آنها برای تشخیص داده شدن باید با قالب یک چهره همخوانی داشته‌باشند (که خطاهایی در این همخوانی هم وجود دارد). برای تشخیص چهره، الگوریتم، برسی تصویر را از بالا سمت چپ شروع کرده و به سمت پایین حرکت می‌کند و تصویر را در قالب خانه‌هایی کوچک از داده‌ها برسی می‌کند. سپس درباره هر قطعه این سوال از خود می‌پرسد: آيا این تصویر‌‌ِ یک چهره است؟ و در نهایت اگر خانه‌ای شبیه به چهره بود آن را ثبت می‌کند. برای درک بهتر این موضوع می‌توان یک پازل را در نظر گرفت؛ پازل یک تصویر است که به چندین خانه یا قطعه کوچکتر تقسیم شده‌است، حال اگر شما بخواهید در تصویر اصلی یک چهره را پیدا کنید، باید به ترتیب هر یک از قطعه‌های کوچک پازل را برسی کرده و در صورت وجود چهره آن را ثبت کنید. اما مشکل اینجاست که الگوریتم باید هر قطعه از تصویر را با 6000 طبقه‌بندی موجود تطابق دهد و این امر سبب افزایش حجم محاسبات می‌شود.

برای حل این مسئله، OpenCV از cascades استفاده می‌کند. حال casdcases چیست؟ بهترین جواب در لغت‌نامه این است: یک آبشار یا یک سری از آبشار‌ها.

Cascades در عمل

اگرچه تئوری تشخیص چهره پیچیده بنظر می‌رسد. اما در عمل بسیار ساده‌است. Cascades دارای گروهی از فایل‌های XML می‌باشند که این فایل‌ها دارای داده‌های مورد نیاز برای تشخیص اشیاء مختلف نظیر چهره، بدن، توپ و... هستند. کافیست فایل مورد نظر برای تشخیص شیء دلخواهتان را در کد وارد ‌کنید و OpenCV آن شیء را درون تصاویر تشخیص می‌دهد.

نصب OpenCV

توجه داشته باشید که این کتابخانه فقط از نسخه 3.6 به پایین پشتیبانی می‌کند. برای نصب آن، در Windows دستور زیر را در Command Prompt وارد کنید:

python –m pip install opencv-python

در Linux نیز دستور‌های زیر را وارد کنید:

sudo apt-get python3-pip python3-opencv

pip install opencv-python

برای اطمینان از نصب کتابخانه، وارد IDLE پیش‌فرض پایتون شده و دستور زیر را وارد کنید:

import cv2

اگر خطایی دریافت نکردید می‌توانید مراحل بعد را دنبال کنید.

نوشتن کد تشخیص چهره

قبل از هرچیز می‌توانید فایل XML مرتبط با تشخیص چهره را از اینجا دانلود کنید.

در ابتدا باید مقادیر لازم و آدرس دهی های لازم را در کد وارد کنیم:

import cv2
imagePath = "test.jpg" 
cascPath = "haarcascade_frontalface_default.xml"

در خط اول پکیج‌ مورد نیاز را وارد کرده و در خط دوم آدرس عکس دلخواه خود و در خط سوم مسیر فایل XML دانلود شده را وارد می‌کنیم.

faceCascade = cv2.CascadeClassifier(cascPath)

حال کلاس لازم برای تشخیص چهره را با استفاده از بارگذاری فایل XML مربوطه ایجاد می‌کنیم.

image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

در خط اول با استفاده از تابع imread، فایل عکس مورد نظر را بارگذاری کرده و در قالب یک ماتریس 3 بعدی داخل متغییر image قرار می‌دهیم.

کتابخانه OpenCV فقط قادر به تشخیص اشیاء در تصاویر سیاه سفید می‌باشد پس در خط دوم تصویر رنگی را به تصویر سیاه و سفید تبدیل می‌کنیم.

faces = faceCascade.detectMultiScale(
    gray,
    scaleFactor=1.1,
    minNeighbors =5,
    minSize=(30, 30)
)

این تابع درواقع بخش کلیدی برنامه ما می‌باشد که عملیات تشخیص چهره را انجام می‌دهد. اما بیاید نگاهی به پارامترهای ورودی بیاندازیم:

  1. اولین پارامتر متغییر gray یا همان تصویر سیاه سفید ما می‌باشد.
  2. گاه ممکن است یک چهره در تصویر نزدیک‌تر از دیگر چهره‌ها درون تصویر باشد و بزرگتر بنظر برسد؛ scaleFactor معیاری برای متعادل کردن این اختلاف اندازه است.
  3. الگوریتم تشخیص چهره از حرکت پنچره‌ای برای تشخیص استفاده می‌کند. پارامتر minNeighbors تعیین می‌کند که در عملیات تشخیص، به چند پنجره نزدیک پنجره اصلی توجه شود. همچنین minSize اندازه آن پنجره‌ها را تعیین می‌کند.

در نهایت این تابع یک لیست از مشخصات مکانی چهره‌های موجود در تصویر را برمی‌گرداند.

print("Found {0} faces!".format(len(faces)))
# Draw a rectangle around the faces
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)

حال با استفاده از مشخصات مکانی چهره‌ها نسبت به تصویر اصلی، مستطیل‌هایی دور آن‌ها رسم ‌می‌کنیم تا مشخص شود که این تشخیص‌ها درست بوده‌اند یا خیر. توجه داشته باشید که در اینجا با استفاده از تابع rectangle از کتابخانه OpenCV عملیات رسم را روی تصویر اصلی (رنگی) انجام می‌دهیم. زیرا در هنگام تبدیل عکس رنگی به سیاه سفید، ابعاد آن تغییری پیدا نمی‌کند و در نتیجه مشخصات مکانی چهره نیز ثابت می‌ماند.

مشخصات مکانی شامل نقطه عرضی (x) و نقطه طولی (y) که موقعیت را نشان می‌دهد و اندازه عرض (w) و اندازه طول (h) که ابعاد چهره را نشان می‌دهد، می‌باشد.

cv2.imshow("Faces found", image)
cv2.waitKey(0)

حال با استفاده از تابع imshow تصویر نهایی را نمایش می‌دهیم. و با متد waitKey منتظر می‌مانیم تا کاربر کلیدی را فشار دهد.

برسی نتایج

ابتدا اطمینان حاصل کنید که فایل تصویر و همچنین فایل XML در کنار فایل اصلی کد پایتون قرار گرفته باشند. اگر فایل‌های شما در مسیر دیگری وجود دارند حتما آدرس صحیح فایل را در ابتدای کد وارد کنید و توجه داشته باشید که در آدرس‌ها به جای استفاده از علامت Backslash از علامتSlash  استفاده کنید.

برای مثال بجای:

C:\Python\Project\test.jpg

بنویسید:

C:/Python/Project/test.jpg

همانطور که در تصویر بالا مشاهده می‌کنید برنامه به خوبی کار می‌کند. حال تصویر دیگری را تست می‌کنیم.

در تصویر بالا دو خطا وجود دارد. برنامه به اشتباه دو بخش از تصویر را به عنوان چهره شناسایی کرده‌است. برای حل این مشکل پارامتر scaleFactor را به مقدار 1.35 تغییر می‌دهیم.

مشاهده می‌کنید که خطا رفع شده و فقط چهره‌ها انتخاب شده‌اند. اما چه اتفاقی افتاد؟ همانطور که در ابتدای مقاله گفته‌شد، ممکن است چهره‌ها در جایگاه‌های مختلفی درون تصویر قرار بگیرند که این امر گاهی سبب بروز خطا می‌شود. همچنین کیفیت تصویر داده شده نیز در دقت تشخیص نقش دارد. این خطا را می‌توان با تعیین scaleFactor مناسب حل کرد.

لازم به ذکر است که در روش یادگیری ماشین، هیچگاه تشخیص با دقت 100٪ اتفاق نمی‌افتد.

منبع

مقالات پیشنهادی

  • ایجاد افزونه کروم با استفاده از پایتون

    تا به حال از افزونه‌های کروم استفاده کرده‌اید؟ اگر جواب‌تان بله است، پس مطمئنا تا به حال از خودتان پرسیده‌اید که این افزونه‌ها چگونه ساخته می‌شود. اگر...

    ارسطو عباسی
  • ایجاد Website Blocker با استفاده از پایتون

    درست است که اپلیکیشن‌های مختلف بسیاری برای بلاک کردن وبسایت‌ها وجود دارد، اما چرا وقتی خودتان می‌توانید آن را بنویسید، سراغ دیگر اپلیکیشن‌ها می‌روید؟...

    ارسطو عباسی