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

۵۲۴۱ بازدید
آخرین به‌روزرسانی: ۰۵ مهر ۱۴۰۲
زمان مطالعه: ۱۳ دقیقه
تشخیص چهره در پایتون با OpenCV و Dlib — از صفر تا صد

در این راهنما با روش ایجاد و اجرای یک الگوریتم تشخیص چهره در پایتون با استفاده از OpenCV و Dlib آشنا می‌شویم. همچنین برخی قابلیت‌های آن‌ها را برای شناسایی همزمان چشم‌ها و دهان روی چهره‌های مختلف معرفی خواهیم کرد. در این مقاله روش پیاده‌سازی مقدماتی تشخیص چهره را به طور کامل توضیح می‌دهیم که شامل ابزارهای طبقه‌بندی آبشاری، پنجره‌های HOG، و CNN-های یادگیری عمیق می‌شود.

997696

برای مشاهده مخزن گیت‌هاب این مقاله به این لینک (+) مراجعه کنید.

مقدمه‌‌

ما در این مطلب از OpenCV استفاده خواهیم کرد که یک کتابخانه متن‌باز برای بینایی ماشین است و به زبان ++C/C نوشته شده است. این کتابخانه اینترفیس‌هایی در زبان‌های ++C، پایتون و جاوا دارد. OpenCV از پلتفرم‌های ویندوز، لینوکس، macOS ،iOS و اندروید پشتیبانی می‌کند. برخی از بخش‌های کار نیازمند Dlib هستند که یک کیت ابزار ++C شامل الگوریتم‌های یادگیری ماشین و ابزارهایی برای خلق نرم‌افزارهای پیچیده است.

پیش‌نیازهای تشخیص چهره در پایتون

نخستین مرحله برای شروع کار، نصب OpenCV و Dlib است.

به این منظور دستور زیر را وارد کنید:

pip install opencv-python
pip install dlib

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

/usr/local/lib/python3.7/site-packages/cv2

اگر در نصب Dlib با مشکلاتی مواجه شدید به این مقاله (+) مراجعه کنید.

ایمپورت و مسیر مدل‌ها

ما یک نت‌بوک ژوپیتر/فایل پایتون می‌سازیم و کار خود را با آن آغاز می‌کنیم:

import cv2
import matplotlib.pyplot as plt
import dlib
from imutils import face_utils

font = cv2.FONT_HERSHEY_SIMPLEX

طبقه‌بندی آبشاری

ابتدا به بررسی طبقه‌بندی آبشاری می‌پردازیم.

نظریه

طبقه‌بندی آبشاری یا آبشارهای مشهور طبقه‌بندی ارتقا یافته به همراه ویژگی‌های شِبه Haar (یا Haar-like feature) عمل می‌کنند و یک کاربرد خاص از «یادگیری گروهی» (ensemble learning) محسوب می‌شوند که boosting نام دارند. این ابزارها به طور عمده روی طبقه‌بندی‌های Adaboost و دیگر مدل‌ها مانند Real Adaboost ،Gentle Adaboost یا Logitboost تکیه دارند.

ابزارهای طبقه‌بندی آبشاری روی چند تصویر نمونه از یک موضوع آموزش می‌بینند. این تصاویر شامل سوژه‌ای است که می‌خواهیم شناسایی کنیم. همچنین از تصاویر دیگر که شامل آن موضوع نیستند نیز استفاده می‌شود.

چگونه می‌توان تشخیص داد که در تصویری چهره انسان وجود دارد یا نه؟ یک الگوریتم به نام فریمورک شناسایی شیء Viola–Jones وجود دارد که شامل همه مراحل مورد نیاز برای شناسایی زنده چهره است. این موارد شامل فهرست زیر می‌شوند:

  • گزینش ویژگی Haar: ویژگی‌هایی هستند که از موجک‌های Haar مشتق شده‌اند.
  • ایجاد تصویر یکپارچه
  • آموزش Adaboost
  • ابزارهای طبقه‌بندی آبشاری

اگر می‌خواهید مقاله اصلی Viola-Jones را ببینید، به این لینک (+) مراجعه کنید.

گزینش ویژگی Haar

برخی ویژگی‌های مشترک وجود دارند که در همه چهره‌های انسانی می‌توان مشاهده کرد:

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

این خصوصیات به نام ویژگی‌های Haar نامیده می‌شوند. فرایند استخراج ویژگی مانند زیر است:

تشخیص چهره در پایتون

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

تشخیص چهره در پایتون

سپس این مستطیل را به عنوان یک کرنل کانولوشنی روی کل تصویر اعمال می‌کنیم. برای این که رویکرد جامعی داشته باشیم، باید همه ابعاد و موقعیت‌های ممکن برای هر کرنل را اعمال کنیم. یک تصویر ساده 24 در 24 پیکسل، معمولاً منتهی به 160،000 ویژگی می‌شود که هر یک از جمع/تفریق کردن مقادیر پیکسل‌ها به دست آمده‌اند. بدین ترتیب امکان تشخیص چهره زنده از دست می‌رود. بنابراین سؤال این است که این فرایند چگونه عملیاتی می‌شود؟

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

ویژگی‌های مستطیل با استفاده از مفهوم تصویر یکپارچه محاسبه می‌شوند که روشی بسیار سریع‌تر است. در مورد این روش در بخش بعدی بیشتر توضیح خواهیم داد.

تشخیص چهره در پایتون

چند نوع از مستطیل‌ها وجود دارند که می‌توان برای استخراج ویژگی‌های Haar مورد استفاده قرار داد. این موارد شامل فهرست زیر هستند:

  • ویژگی دو مستطیلی به تفاضل بین مجموع مقادیر پیکسل‌ها درون نواحی مستطیلی می‌پردازد و به طور عمده برای تشخیص لبه‌ها (در تصویر زیر a و b) استفاده می‌شود.
  • ویژگی سه مستطیلی مجموع ناحیه درون محدوده مستطیل‌های کناری را محاسبه می‌کند که از مجموع مستطیل میانی کسر می‌شوند و به طور عمده برای شناسایی خطوط (c و d) استفاده می‌شود.
  • ویژگی چهار مستطیلی تفاضل بین جفت‌های قطری مستطیل‌ها (e) را محاسبه می‌کند.

تشخیص چهره در پایتون

اینک که ویژگی‌ها گزینش شده‌اند، آن‌ها را با استفاده از طبقه‌بندی Adaboost روی مجموعه‌ای از تصاویر آموزشی اعمال می‌کنیم. بدین ترتیب مجموعه‌ای از طبقه‌بندی‌های ضعیف با هم ترکیب می‌شود تا یک مدل گروهی دقیق را تشکیل دهند. با استفاده از 200 ویژگی (به جای 160،000 ویژگی اولیه) میزان دقتی برابر با 95% به دست می‌آید. ما در این نوشته از 6000 ویژگی استفاده کرده‌ایم.

تصویر یکپارچه

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

فرض کنید می‌خواهیم ویژگی‌های مستطیلی را در یک پیکسل مفروض با مختصات x و y محاسبه کنیم. سپس تصویر یکپارچه پیکسل را در مجموع پیکسل‌های سمت بالا و سمت چپ پیکسل محاسبه می‌کنیم:

در فرمول فوق (ii(x،y تصویر یکپارچه و (i(x،y تصویر اصلی است.

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

تشخیص چهره در پایتون

که (s(x،y مجموع ردیف تجمعی و s(x−1)=0، ii(−1،y)=0 است.

این رابطه چه فایده‌ای دارد؟ تصور کنید ناحیه D وجود دارد که در آن می‌خواهیم مجموع پیکسل‌ها را محاسبه کنیم. ما سه ناحیه دیگر را نیز به صورت A ،B و C تعریف کرده‌ایم.

  • مقدار تصویر اصلی در نقطه 1 برابر با مجموعه پیکسل‌ها در مستطیل A است.
  • مقدار مربوطه در نقطه 2 برابر با A + B است.
  • مقدار مربوطه در نقطه 3 برابر با A + C است.
  • مقدار مربوطه در نقطه 4 برابر با A + B + C + D است.

از این رو مجموع پیکسل‌ها در ناحیه D را می‌توان با استفاده از فرمول زیر محاسبه کرد:

4+1−(2+3)

با استفاده از یک گذر می‌توان مقدار درون یک مستطیل را با استفاده از تنها 4 ارجاع آرایه‌ای محاسبه کرد:

تشخیص چهره در پایتون

باید بدانید که مستطیل‌ها عملاً ویژگی‌های کاملاً ساده‌ای هستند، اما اهمیت زیادی در تشخیص چهره دارند. فیلترهای Steerable هنگامی که با مسائل پیچیده سر و کار داریم، انعطاف‌پذیری بیشتری دارند.

تشخیص چهره در پایتون

یادگیری تابع طبقه‌بندی با استفاده از Adaboost

با فرض وجود یک مجموعه برچسب خورده از تصاویر آموزشی (مثبت یا منفی) Adaboost به صورت زیر مورد استفاده قرار می‌گیرد:

  • یک مجموعه کوچک از ویژگی‌ها را انتخاب کنید.
  • الگوریتم طبقه‌بندی را آموزش دهید.

از آنجا که اغلب ویژگی‌ها در میان 160،000 ویژگی نامرتبط تصور شده‌اند؛ الگوریتم یادگیری ضعیف که با استفاده از مدل boosting ساختیم طوری طراحی شده است که ویژگی مستطیلی منفردی را انتخاب کند که مثال‌های مثبت و منفی را به بهترین روش از هم جدا می‌کند.

طبقه‌بندی آبشاری

با این که فرایند توصیف شده فوق کاملاً کارآمد است، اما هنوز یک مشکل عمده بر سر راه آن پابرجا است. در یک تصویر اغلب بخش‌ها را قسمت‌های غیر از چهره تشکیل می‌دهند. دادن اهمیت یکسان به همه بخش‌های چنین تصویری بی‌معنی است، چون باید تمرکز عمده روی ناحیه‌ای باشد که احتمال وجود چهره بیشتر است. Viola و Jones در روش خود به نرخ شناسایی بالایی دست یافتند و در عین حال زمان محاسبه را با استفاده از طبقه‌بندی‌های آبشاری کاهش دادند.

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

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

  • اگر طبقه‌بندی نخست مثبت باشد، به طبقه‌بندی دوم می‌رویم.
  • اگر طبقه‌بندی دوم مثبت باشد، به طبقه‌بندی سوم می‌رویم.
  • و همین طور تا آخر.

هر نتیجه منفی در یک نقطه، منتهی به رد پنجره فرعی می‌شود که احتمالاً شامل یک چهره است. طبقه‌بندی اول اغلب مثال‌های منفی را با هزینه محاسباتی پایین کاهش می‌دهد و طبقه‌بندی‌های بعدی مثال‌های منفی بعدی را که هزینه بالاتری دارند با استفاده از توان محاسباتی بالاتر حذف می‌کنند.

تشخیص چهره در پایتون

طبقه‌بندی‌ها با استفاده از Adaboost آموزش داده می‌شوند و حد آستانه طوری تعیین می‌شود که نرخ تشخیص نادرست کمینه شود. زمانی که چنین مدلی را آموزش می‌دهیم، متغیرها به صورت زیر هستند:

  • تعداد مراحل طبقه‌بندی
  • تعداد ویژگی‌ها در هر مرحله
  • حد آستانه در هر مرحله

خوشبختانه در OpenCV، کل مدل از قبل برای تشخیص چهره تعلیم یافته است.

ایمپورت‌ها

مرحله بعدی این است که وزن‌های از قبل آموزش‌یافته را مکان‌یابی کنیم. ما از مدل‌های از پیش آموزش‌دیده برای تشخیص چهره، چشم‌ها و دهان استفاده خواهیم کرد. بسته به این که از چه نسخه‌ای از پایتون استفاده می‌کنید فایل‌های مربوطه باید در چنین مکان‌هایی باشند:

/usr/local/lib/python3.7/site-packages/cv2/data

الگوریتم‌های طبقه‌بندی آبشاری را به روش زیر اعلان می‌کنیم:

cascPath = "/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_default.xml"
eyePath = "/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_eye.xml"
smilePath = "/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_smile.xml"

faceCascade = cv2.CascadeClassifier(cascPath)
eyeCascade = cv2.CascadeClassifier(eyePath)
smileCascade = cv2.CascadeClassifier(smilePath)

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

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

1# Load the image
2gray = cv2.imread('face_detect_test.jpeg', 0)
3plt.figure(figsize=(12,8))
4plt.imshow(gray, cmap='gray')
5plt.show()

تشخیص چهره در پایتون

سپس چهره را تشخیص داده و یک مستطیل پیرامون آن اضافه می‌کنیم:

1# Detect faces
2faces = faceCascade.detectMultiScale(
3gray,
4scaleFactor=1.1,
5minNeighbors=5,
6flags=cv2.CASCADE_SCALE_IMAGE
7)
8# For each face
9for (x, y, w, h) in faces: 
10    # Draw rectangle around the face
11    cv2.rectangle(gray, (x, y), (x+w, y+h), (255, 255, 255), 3)

در ادامه فهرستی از پارامترهای مشترک را برای تابع detectMultiScale مشاهده می‌کنید:

  • scaleFactor: پارامتری است که میزان کاهش اندازه تصویر را در هر مقیاس‌بندی تصویر تعیین می‌کند.
  • minNeighbors: این پارامتر تعداد همسایگی‌های هر مستطیل نامزد که باید حفظ شوند را تعیین می‌کند.
  • minSize: کمینه اندازه ممکن برای شیء است. شیءهای کوچک‌تر از آن نادیده گرفته می‌شوند.
  • maxSize: بیشینه ممکن برای اندازه شیء است. شیءهای بزرگ‌تر از آن نادیده گرفته می‌شوند.

در نهایت نتیجه نمایش پیدا می‌کند:

1plt.figure(figsize=(12،8))
2plt.imshow(gray، cmap='gray')
3plt.show()

تشخیص چهره در پایتون

چنان که مشاهده می‌کنید، تشخیص چهره روی تصویر تست ما به خوبی عمل کرده است. در ادامه آن را به صورت عملکرد همزمان (آنی) تست می‌کنیم.

تشخیص چهره آنی

در این بخش پیاده‌سازی تشخیص چهره زنده را در پایتون بررسی خواهیم کرد. نخستین گام باز کردن دوربین و دریافت ویدئو است. سپس تصویر را به یک تصویر خاکستری تبدیل می‌کنیم. این کار برای کاهش ابعاد تصویر ورودی صورت می‌گیرد. در واقع به جای 2 نقطه برای هر پیکسل که با رنگ‌های قرمز، سبز و آبی توصیف می‌شوند، یک تبدیل خطی ساده استفاده می‌شود:

این وضعیت به صورت پیش‌فرض در OpenCV پیاده‌سازی شده است:

1video_capture = cv2.VideoCapture(0)
2while True:
3    # Capture frame-by-frame
4    ret, frame = video_capture.read()
5    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

اینک از متغیر faceCascade که در بخش قبلی تعریف کردیم استفاده می‌کنیم. این متغیر شامل یک الگوریتم از پیش آموزش‌دیده است و آن را روی یک تصویر خاکستری اعمال می‌کنیم.

1faces = faceCascade.detectMultiScale(
2        gray,
3        scaleFactor=1.1,
4        minNeighbors=5,
5        minSize=(30, 30),
6        flags=cv2.CASCADE_SCALE_IMAGE
7        )

برای هر چهره‌ای که تشخیص داده شود، یک مستطیل پیرامون چهره ترسیم می‌شود:

1for (x, y, w, h) in faces:
2        if w > 250 :
3            cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 3)
4            roi_gray = gray[y:y+h, x:x+w]
5            roi_color = frame[y:y+h, x:x+w]

در مورد هر دهان که تشخیص داده می‌شود نیز یک مستطیل پیرامون آن رسم می‌شود:

1smile = smileCascade.detectMultiScale(
2        roi_gray,
3        scaleFactor= 1.16,
4        minNeighbors=35,
5        minSize=(25, 25),
6        flags=cv2.CASCADE_SCALE_IMAGE
7    )
8    for (sx, sy, sw, sh) in smile:
9        cv2.rectangle(roi_color, (sh, sy), (sx+sw, sy+sh), (255, 0, 0), 2)
10        cv2.putText(frame,'Smile',(x + sx,y + sy), 1, 1, (0, 255, 0), 1)

همچنین برای هر چشم شناسایی شده یک مستطیل در پیرامونش ترسیم می‌شود:

1eyes = eyeCascade.detectMultiScale(roi_gray)
2    for (ex,ey,ew,eh) in eyes:
3        cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
4        cv2.putText(frame,'Eye',(x + ex,y + ey), 1, 1, (0, 255, 0), 1)

سپس تعداد کل چهره‌ها شمارش شده و تصویر نهایی نمایش پیدا می‌کند:

1cv2.putText(frame,'Number of Faces : ' + str(len(faces)),(40, 40), font, 1,(255,0,0),2)      
2    # Display the resulting frame
3    cv2.imshow('Video', frame)

زمانی که می‌خواهیم از دوربین خارج شویم یک گزینه خروج نیز پیاده‌سازی می‌کنیم تا با ارسال حرف q فعال شود:

1if cv2.waitKey(1) & 0xFF == ord('q'):
2        break

در نهایت هنگامی که همه کارها انجام یافت، دریافت ویدئو قطع می‌شود و همه پنجره‌ها بسته می‌شوند. البته بستن پنجره‌ها در سیستم Mac با برخی مشکلات مواجه می‌شود که ممکن است نیازمند توقف پردازش پایتون در Activity Manager باشد:

1video_capture.release()
2cv2.destroyAllWindows()

جمع‌بندی

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

1import cv2
2
3cascPath = "/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_default.xml"
4eyePath = "/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_eye.xml"
5smilePath = "/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_smile.xml"
6
7faceCascade = cv2.CascadeClassifier(cascPath)
8eyeCascade = cv2.CascadeClassifier(eyePath)
9smileCascade = cv2.CascadeClassifier(smilePath)
10
11font = cv2.FONT_HERSHEY_SIMPLEX
12video_capture = cv2.VideoCapture(0)
13
14while True:
15    # Capture frame-by-frame
16    ret, frame = video_capture.read()
17
18    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
19
20    faces = faceCascade.detectMultiScale(
21        gray,
22        scaleFactor=1.1,
23        minNeighbors=5,
24        minSize=(200, 200),
25        flags=cv2.CASCADE_SCALE_IMAGE
26    )
27
28    # Draw a rectangle around the faces
29    for (x, y, w, h) in faces:
30        cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 3)
31            roi_gray = gray[y:y+h, x:x+w]
32            roi_color = frame[y:y+h, x:x+w]
33            cv2.putText(frame,'Face',(x, y), font, 2,(255,0,0),5)
34
35    smile = smileCascade.detectMultiScale(
36        roi_gray,
37        scaleFactor= 1.16,
38        minNeighbors=35,
39        minSize=(25, 25),
40        flags=cv2.CASCADE_SCALE_IMAGE
41    )
42
43    for (sx, sy, sw, sh) in smile:
44        cv2.rectangle(roi_color, (sh, sy), (sx+sw, sy+sh), (255, 0, 0), 2)
45        cv2.putText(frame,'Smile',(x + sx,y + sy), 1, 1, (0, 255, 0), 1)
46
47    eyes = eyeCascade.detectMultiScale(roi_gray)
48    for (ex,ey,ew,eh) in eyes:
49        cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
50        cv2.putText(frame,'Eye',(x + ex,y + ey), 1, 1, (0, 255, 0), 1)
51
52    cv2.putText(frame,'Number of Faces : ' + str(len(faces)),(40, 40), font, 1,(255,0,0),2)      
53    # Display the resulting frame
54    cv2.imshow('Video', frame)
55
56    if cv2.waitKey(1) & 0xFF == ord('q'):
57      break
58
59# When everything is done, release the capture
60video_capture.release()
61cv2.destroyAllWindows()

نتایج

در ویدئوی کوتاه زیر عملکرد پیاده‌سازی تشخیص چهره ما را مشاهده می‌کنید:

تشخیص چهره در پایتون

هیستوگرام گرادیان‌های جهت‌دار (HOG) در Dlib

دومین پیاده‌سازی محبوب برای تشخیص چهره از سوی Dlib ارائه شده و از مفهومی به نام هیستوگرام گرادیان‌های جهت‌دار (HOG) بهره می‌گیرد. در این بخش به پیاده‌سازی روش اصلی پیشنهاد شده در مقاله Dalal و Triggs (+) می‌پردازیم.

نظریه

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

ویژگی‌های استخراج شده، توزیع‌ها (هیستوگرام‌ها)-ی جهت‌گیری گرادیان‌ها (یا گرادیان‌های جهت‌دار) از تصویر هستند. گرادیان‌ها عموماً در بخش‌های لبه و گوشه، مقادیر بالایی دارند و بدین ترتیب به ما امکان می‌دهند که آن نواحی را تشخیص دهیم.

در مقاله اصلی، فرایند کار برای تشخیص بدن انسان به صورت زیر پیاده‌سازی شده است و زنجیره تشخیص به شرح زیر است:

تشخیص چهره در پایتون

پیش‌پردازش

قبل از هر چیز، تصاویر ورودی باید هم‌اندازه باشند. از این رو برش و تغییر مقیاس لازم است. وصله‌هایی که ما در این مقاله استفاده می‌کنیم، دارای نسبت 1:2 هستند و از این رو ابعاد تصاویر ورودی باید برای نمونه 64 در 128 یا 100 در 200 باشد.

محاسبه تصاویر گرادیان

نخستین گام، محاسبه گرادیان‌های افقی و عمودی تصویر از طریق به‌کارگیری کرنل‌های زیر است:

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

گرادیان یک تصویر عموماً اطلاعات غیرضروری را حذف می‌کند. گرادیان تصویری که در بخش فوق در نظر گرفتیم را می‌توان در پایتون به صورت زیر به دست آورد:

1gray = cv2.imread('images/face_detect_test.jpeg', 0)
2im = np.float32(gray) / 255.0
3# Calculate gradient 
4gx = cv2.Sobel(im, cv2.CV_32F, 1, 0, ksize=1)
5gy = cv2.Sobel(im, cv2.CV_32F, 0, 1, ksize=1)
6mag, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True)

شکل را به صورت زیر رسم می‌کنیم:

1plt.figure(figsize=(12،8))
2plt.imshow(mag)
3plt.show()

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

با این حال ما تصویر را پیش‌پردازش نکرده‌ایم.

محاسبه HOG

در ادامه تصویر به سلول‌های 8 در 8 تقسیم می‌شود تا یک بازنمایی فشرده ایجاد شود و HOG در برابر نویز مقاومت بیشتری بیابد. سپس HOG را برای هریک از این سلول‌ها محاسبه می‌کنیم.

برای تخمین جهت گرادیان درون ناحیه، یک هیستوگرام میان 64 مقدار از جهت‌گیری‌های گرادیان (8 در 8) می‌سازیم و بزرگی آن‌ها (64 مقدار دیگر) درون هر ناحیه را نیز محاسبه می‌کنیم. دسته‌های هیستوگرام با زوایای گرادیان از 0 تا 180 درجه مرتبط هستند. در مجموع 9 دسته به صورت 0، 20، 40،... و 160 درجه وجود دارند.

کد فوق دو نوع اطلاعات را در اختیار ما قرار می‌دهد:

  • جهت گرادیان‌
  • بزرگی گرادیان

زمانی که HOG را می‌سازیم، 3 حالت فرعی وجود دارد:

  • زاویه کمتر از 160 درجه باشد و در نیمه بین 2 طبقه قرار نگرفته باشد. در چنین مواردی، این زاویه در دسته مناسب HOG اضافه می‌شود.
  • زاویه کمتر از 60 درجه باشد و دقیقاً بین دو طبقه قرار بگیرد. در چنین حالتی یک مشارکت برابر بین دو طبقه مجاور تصور کرده و بزرگی را به 2 بخش تقسیم می‌کنیم.

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

  • زاویه بزرگ‌تر از 160 درجه باشد. در چنین حالت‌هایی تصور می‌کنیم که آن پیکسل به صورت قائم بر 160 و تا 0 درجه مشارکت دارد.

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

HOG برای هر سلول 8 در 8 به صورت زیر به دست می‌آید:

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

نرمالسازی بلوک

در نهایت، یک بلوک 16 در 16 را می‌توان برای نرمالسازی تصویر و برای مثال حذف تأثیر نوردهی اعمال کرد. این نتیجه به سادگی با تقسیم کردن هر مقدار HOG با اندازه 8 در 8 بر L2-norm مربوط به بلوک HOG 16 در 16 که شامل آن است صورت می‌گیرد. در واقع این یک بردار ساده با طول 9*4 = 36 است.

در نهایت همه بردارهای 36 در 1 در یک بردار بزرگ تجمیع می‌شوند و کار به پایان می‌رسد. بدین ترتیب بردار ویژگی به دست می‌آید و با استفاده از آن می‌توان یک الگوریتم طبقه‌بندی SVM نرم (C=0.01) را آموزش داد.

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

پیاده‌سازی این روش کاملاً سر راست است:

1face_detect = dlib.get_frontal_face_detector()
2rects = face_detect(gray, 1)
3for (i, rect) in enumerate(rects):
4(x, y, w, h) = face_utils.rect_to_bb(rect)
5    cv2.rectangle(gray, (x, y), (x + w, y + h), (255, 255, 255), 3)
6    
7plt.figure(figsize=(12,8))
8plt.imshow(gray, cmap='gray')
9plt.show()

تشخیص چهره در پایتون با OpenCV و Dlib

تشخیص چهره آنی

همانند روش قبلی، پیاده‌سازی آنی این الگوریتم نیز آسان است. ما یک نسخه سبک‌تر از آن را که تنها چهره را تشخیص می‌دهد را پیاده‌سازی کرده‌ایم. Dlib شناسایی نقاط کلیدی چهره را نیز به صورت کاملاً ساده اجرا می‌کند که البته بررسی آن خارج از حیطه این مقاله است:

1video_capture = cv2.VideoCapture(0)
2flag = 0
3
4while True:
5
6    ret, frame = video_capture.read()
7
8    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
9    rects = face_detect(gray, 1)
10
11    for (i, rect) in enumerate(rects):
12
13        (x, y, w, h) = face_utils.rect_to_bb(rect)
14
15        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
16
17        cv2.imshow('Video', frame)
18
19    if cv2.waitKey(1) & 0xFF == ord('q'):
20        break
21
22video_capture.release()
23cv2.destroyAllWindows()

شبکه عصبی کانولوشنی در Dlib

آخرین روش که در این مقاله برای تشخیص چهره بررسی می‌کنیم مبتنی بر شبکه‌های عصبی کانولوشنی (CNN) است. برای پیاده‌سازی این روش از نتایج این مقاله (+) در مورد شناسایی شیء (Max-Margin (MMOD بهره جسته‌ایم.

اندکی از نظریه روش

شبکه‌های عصبی کانولوشنی (CNN) شبکه‌های عصبی پیش‌خور (feed-forward) هستند که به طور عمده برای بینایی ماشین استفاده می‌شوند. این شبکه‌ها یک پیش-آموزش خودکار را نیز همراه با بخش شبکه عصبی فشرده ارائه می‌کنند. CNN-ها انواع خاصی از شبکه‌های عصبی برای پردازش داده‌ها با فناوری شبه grid هستند. معماری CNN از کورتکس بینایی جانداران الهام گرفته است.

در رویکردهای قبلی، بخش عمده‌ای از کار مربوط به انتخاب فیلترها برای ایجاد ویژگی‌هایی جهت استخراج بیشینه ممکن اطلاعات از تصاویر بوده است. با ظهور یادگیری عمیق و ظرفیت‌های محاسباتی بالاتر این کار اکنون به صورت خودکار صورت می‌گیرد. نام CNN از این واقعیت ناشی می‌شود که ورودی تصویر اولیه با یک مجموعه از فیلترها پیچش (convolve) می‌یابد. پارامتری که باید انتخاب کرد، تعداد فیلترهایی که باید اعمال شوند و ابعاد فیلترها است. بُعد فیلتر به نام طول stride نامیده می‌شود. مقادیر معمول برای این stride بین 2 و 5 هستند:

خروجی CNN در این مورد خاص یک طبقه‌بندی باینری است که در صورت وجود چهره مقدار 1 و در غیر این صورت مقدار 0 می‌گیرد.

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

برخی اجزای این رویکرد در پیاده‌سازی تغییر می‌یابند. نخستین گام، دانلود کردن مدل از پیش آموزش‌دیده (+) است. وزن‌ها را به پوشه خود منتقل و dnnDaceDetector را تعریف کنید:

dnnFaceDetector = dlib.cnn_face_detection_model_v1("mmod_human_face_detector.dat")

سپس مشابه روشی که تا به اینجا عمل کردیم پیش می‌رویم:

1rects = dnnFaceDetector(gray, 1)
2for (i, rect) in enumerate(rects):
3    x1 = rect.rect.left()
4    y1 = rect.rect.top()
5    x2 = rect.rect.right()
6    y2 = rect.rect.bottom()
7    # Rectangle around the face
8    cv2.rectangle(gray, (x1, y1), (x2, y2), (255, 255, 255), 3)
9plt.figure(figsize=(12,8))
10plt.imshow(gray, cmap='gray')
11plt.show()

تشخیص چهره در پایتون با OpenCV و Dlib

تشخیص چهره آنی

در نهایت نسخه آنی تشخیص چهره CNN را پیاده‌سازی خواهیم کرد:

1video_capture = cv2.VideoCapture(0)
2flag = 0
3
4while True:
5    # Capture frame-by-frame
6    ret, frame = video_capture.read()
7
8    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
9    rects = dnnFaceDetector(gray, 1)
10
11    for (i, rect) in enumerate(rects):
12
13        x1 = rect.rect.left()
14        y1 = rect.rect.top()
15        x2 = rect.rect.right()
16        y2 = rect.rect.bottom()
17
18        # Rectangle around the face
19        cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
20
21    # Display the video output
22    cv2.imshow('Video', frame)
23
24    # Quit video by typing Q
25    if cv2.waitKey(1) & 0xFF == ord('q'):
26        break
27
28video_capture.release()
29cv2.destroyAllWindows()

کدام روش را باید انتخاب کرد؟

سؤال دشواری است و برای پاسخ به آن باید دو معیار مهم زیر را در نظر گرفت:

  • زمان محاسبات
  • دقت

اگر سرعت را معیار قرار دهیم، HoG سریع‌ترین الگوریتم به نظر می‌رسد و سپس طبقه‌بندی آبشار Haar و CNN قرار دارند.

با این حال، CNN-ها و Dlib دقیق‌ترین الگوریتم‌ها هستند. HoG نیز عملکرد خوبی دارد، اما مشکلاتی در شناسایی چهره‌های کوچک دارد. طبقه‌بندی HaarCascade نیز به خوبی HoG عمل می‌کند. اگر می‌خواهید تشخیص سریعی در ویدئوهای زنده خود داشته باشید پیشنهاد می‌کنیم از روش HoG استفاده کنید.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۱۴ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
towardsdatascience
۳ دیدگاه برای «تشخیص چهره در پایتون با OpenCV و Dlib — از صفر تا صد»

سلام من از ویندوز ده استفاده می کنم وقتی نی خوام dlibرو نصب کنم خطای میده مبنی به اینکه باید ویژوال استدیو رو نصب کنم این یعنی من حتما باید این برنامه رو نصب کنم یا راه حل دیگه ای داره ممنون میشم اگه راهنمایی کنید

با سلام. من هم همچین مشکلی داشتم.
به لینک زیر بروید و کتابخانه مطابق با ورژن پایتون نصب شده روی سیستمان نصب کنید.
https://github.com/sachadee/Dlib

البته الگوریتمی face detection که امروزه معمولا ازش استفاده میشه MTCNN هست که سه شبکه CNN داره که هم real-time هست و هم دقت بسیار بهتری در تشخیص صورت های کوچک نسبت به روش های بالا داره…

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *