تشخیص چهره کلاسیک و جدید(deeplearning)

Face verification: همانطور که قبلا توضیح داده شد این الگوریتم می گوید این دو نفر یکی هستند یا خیر.

Face identification: این الگوریتم می گوید این دو نفر یکی هستند.

مراحل شناختی برای face identification : (برای مشاهده گیف مربوطه به http://www.iamwire.com/2017/03/modern-face-recognition-deep-learning/149697 مراجعه شود.)

  1. در ابتدا باید face تشخیص داده شود و سپس آن را crop می کنیم.
  2. در این مرحله alignment روی face انجام می شود.
  3. Embedding تصویر alignment شده مرحله قبل را درمی آوریم.
  4. مقایسه برای شناخت شخص

طبق گفته های Andrew NG برای face detection  باید حتما مراحل detection و crop چهره را انجام بدهیم تا performance خوبی داشته باشیم.

Alignment: در مقاله 2014 گروه آکسفورد برای انجام alignment یک پروسس بسیار پیچیده انجام می دادند که در این پروسس از تصویر داده شده یک مدل سه بعدی در می آورد و سپس این مدل سه بعدی را frontal می کرد و به انجام همه این عملیات alignment می گفت. اما در مقالات بعدی از alignment های ساده تری استفاده شد؛ برای مثال facenet تنها چهره را کراپ می کرد و آن را وسط صفحه می انداخت. اما با توجه به تجارب بدست آمده، مشخص شده که پروسس های پیچیده برای alignment  نه تنها performance را بهتر نمی کند بله گاهی وقتا بدتر هم می کند.

در ادامه می خواهیم بررسی کنیم که چطور می توانface  را detect کرد. در ابتدا یک روش کلاسیک را بررسی خواهیم کرد.

روش HAAR Cascade : در بسیاری از device هایی که face  را detect می کند و عکس می گیرد از این روش استفاده می شود که روشی بسیار سریع است و برای آن از opencv  کلاسیک استفاده شده است.

در این روش یک سری feature استخراج می شود که می توانند Binary Classification انجام دهند. درنهایت به وسیله نتایج همه آن ها detection انجام می شود.

در واقع با HARR Cascade مثلا می توان دریافت که این تصویر چشم هست یا خیر.

Haar features:

Feature های پایه در haar features شامل مواردی است که در تصویر بالا سمت راست دیده می شود. که همان طور که در عکس های سمت چپ می بینید یک لبه یا یک خط را detect می کنند. در واقع چیزی که از تصویر بالا برداشت می شود این است که اگر بخواهیم چشم را detect کنیم احتمالا feature ای که در تصویر دوم مشاهده می کنید به کار می آید و اگر بخواهیم بینی را detect کنیم (با توجه به سایه روشن های روی بینی) احتمالا feature ای که در تصویر سوم مشاهده می شود به کار می آید.

برای استفاده از این feature ها هر کدام ها را با تمام سایز های مختلف را روی عکس حرکت می دهند.

دیتاست این classification دارای دو کلاس face و nonface است و عکس را در سایز 24*24 در نظر می گیرد. در مجموع 180000 feature برای این کار generate کرده است و چون اگر بخواهد از تمام این feature ها در قسمت های مختلف تصویر استفاده کند overload محاسباتی اش زیاد می شود، از تکنیکی به نامintegral image استفاده کرده است و بسیاری از محاسبات تکراری را حذف کرده است.

یک سری ازfeature ها مربوط هستند و یک سری دیگر نامربوط؛ مثلاfeature  هایی که روی face نیفتاده باشند نامربوط هستند.

چون feature هایی که پیدا کرده بودند بسیار زیاد بود(180000)  در مقاله ای دیگر به نام adaBoost آمده اند feature های مهم تر را استخراج کرده اند که حدود 6000 تا بودند. برای این کار feature ها را بر اساس اهمیت و کارایی شان مرتب کرده اند. در ابتدا مهم ترین feature را روی عکس انداختند و اگر این feature هدف را پیدا نمی کرد بقیه feature ها بررسی نمی شدند. برای مثال اگر مهم ترین feature بینی را تشخیص می داد و بینی ای در تصویر پیدا نمی کرد، نتیجه می گرفتند چهره ای وجود ندارد. اما اگر بینی پیدا می شد وارد گام بعدی Cascade می شد. در گام بعدی تعداد feature هایی که باید بررسی شوند بیشتر می شود.

مراحل استفاده بعد از training:

  1. لود یک classifier
  2. یک عکس لود کرده و به این classifier می دهیم.
  3. اگر چهره ای تشخیص داده شد موقعیت چهره و طول و عرض آن را پیدا میکند.
  4. مستطیل را برای آن موقعیت رسم می کند

برای پیدا کردن HaarCascade ها کافیست HaarCascade opencv را سرچ کرده و به گیت هاب opencv بروید (https://github.com/opencv/opencv/tree/master/data/haarcascades ) در آن جا یک سری xml وجود دارد که انواع مختلف HaarCascade ها برای عملیات گوناگون در آن وجود دارد. با دانلود هرکدام می توان از آن در پروژه استفاده کرد.

در این درس از HaarCascade_frontalface و HaarCascade_eye استفاده شده است و در کنار کد این فایل های را قرار می دهیم.

از cv2.CascadeClassifier برای لود classifier دانلود شده استفاده می شود. در واقع در این قسمت می گوید که classifier بر اساس چه ویژگی هایی ساخته شود. در این مثال که frontalface به آن پاس داده شده است classifier چهره ساخته شده است که اسمش را face_classifier گذاشته ایم.

از RGB2Gray بر روی عکس استفاده می کنیم و عکس را grayscale می کنیم زیرا opencv بیشتر از توابعی استفاده می کند که روی تصاویر grayscale کار می کنند.

در این قسمت از تابع detectMultiScale استفاده شده است؛ چون می خواهیم با scale های مختلف detect کنیم. برای این کار opencv عکس را چند بار resize می کند تا بتواند چهره را تشخیص بدهد و بعد از detect شدن نسبت این عکس به عکس اصلی را پیدا می کند تا موقعیت دقیق چهره را بگوید. در واقع این تابع با یک فاکتوری pyramid درست می کند.

Faces لیستی از لیست هاست که درواقع x, y, w, h چهره های detect شده را در خود دارد.

Scale factor: دومین پارامتر تابع detectMultiScale است که می گوید با چه فاکتوری عکس را resize کند؛ به عنوان مثال وقتی این پارامتر را برابر 1.3 قرار می دهیم یعنی هربار 30 درصد عکس بزرگ تر شود.

Min Neighbors: سومین پارامتر تابع detectMultiScale است که می گوید تا چه حد Neighbor بودن مجاز باشد که معمولا بین 3 تا 6 قرار می دهیم. اگر این مقدار خیلی پایین باشد ممکن است با این مواجه شویم که برای یک چهره دو bounding box در نظر گرفته است و اگر این مقدار خیلی بالا باشد ممکن است چهره را تشخیص ندهد.

حال می خواهیم  علاوه بر چهره، چشم را هم detect کنیم پس باید علاوه بر HaarCascade_frontalface، HaarCascade_eye  را هم لود کنیم.

برای پیدا کردن eye باید اول یک چهره detect شود و در ناحیه چهره باید به دنبال eye باشیم. پس در یک حلقه for ناحیه چهره را به دو صورت رنگی و grayscale (به جهت این که الگوریتم های classifier روی عکس های grayscale بهتر جواب می دهد) جدا می کنیم.

سپس دوباره detectMultiScale را این بار روی چهره کراپ شده صدا می زنیم تا چشم ها را detect کنیم.

سپس با ایجاد for جدید از eye های detect شده و داشتن موقعیت آن ها یک مستطیل روی آنها می کشیم، قاعدتا به ازای هر face دوبار for داخل اجرا می شود.

حال می خواهیم عملیات detect چهره و چشم را به صورت live با camscanner انجام دهیم.

الگوریتم مشابه الگوریتم های قبل عمل می کند. چهره ها را پیدا می کنیم و x,y,w,h را کمی تغییر می دهیم تا چهره به صورت کامل کراپ شود. چهره را کراپ کراپ کرده و کراپ شده را نشان می دهیم.

با توجه به نمودارهای زیر که درواقع الگوریتم هایline  face (چیزهای ساده ای که قبلا به عنوان بدیهیات در نظر گرفته می شد یعنی تقریبا همه می توانستند از ان استفاده کنند مانند haarCascade ) را نشان می دهد که vj در آن همان HaarCasscade می باشد. در این نمودارها به جای آن که نمودار performance کشیده شود، نمودار roc curve کشیده شده است که درواقع roc curve به ازای recall های مختلف persision  های مختلف را می کشد.  recall در واقع تعداد face ها از مجموع همه ی چهره ها را می گوید. (به بیان دیگز چندتا از چهره ها را توانست تشخیص دهد) و persision صحت چهره بودن برایش مهم است. (به عبارتی در persision مهم نیست چند تا از چهره ها تشخیص داده شده است این مهم است که با چه اطمینانی این چهره واقعا چهره است.)

در نمودارهای زیر درواقع هرچه سطح زیر نمودار بیشتر باشد بهتر است.

Multitask-Cascade-CNN از جمله مقاله های submit شده است که کد آن توسط خود نویسنده منتشر شده و افراد دیگر در قالب های تنسورفلویی آن را پیاده سازی کرده اند به همین دلیل ما به بررسی این الگوریتم می پردازیم.

مشکل convolutional neural network این است که اگر بخواهیم فیلتر ها را روی عکس جابه جا کنیم تا چهره را تشخیص بدهیم، تعداد حالت ها زیاد است و deep learning بسیار سنگین است. به همین خاطر ایده های زیادی استفاده شد تا این مشکل حل شود. از جمله این ایده ها این بود که به جای آن که  در تمام نقاط تصویرdetection  بزنیم تنها در جاهایی که ممکن است  چهره باشد بزنیم. می توان threshold الگوریتم Haarcasscade را پایین آورد تا تمام چهره ها را تشخیص دهد (recall را بالا ببریم و اگر precision پایین هم آمد مهم نیست) حالا این چهره های detect شده را اگر به شبکه کانوولووشنالی بدهیم معقول تر است. این ایده ها مربوط به سالهای 2014 و 2016  می باشد.

در سال 2016  تمام مراحل را deep learning کردند به این صورت که در گام اول که resize می باشد یک pyramid تشکیل می دهد. در گام بعدی از شبکه p-Net (proposal network)که یک شبکه کانوولوشنالی فوق العاده سبک است استفاده می شود که فقط نقاط احتمال چهره را در می آورد (علاوه بر چهره ممکن است چیز های نامربوط دیگر را هم درآورد).

در گام بعدی نتایج حاصله از مرحله قبل را کراپ کرده و به شبکه R-Net (Refinement Network) که در این شبکه هم مکان های bounding box ها را تنظیم کرده و هم بعضی از bounding box ها را حذف می کند.

در گام بعد این بار می خواهیم precision را بالا ببریم پس خروجی R-net را به شبکه O-Net(output Network) می دهیم و از بین آنها انتخاب می کند و landmark های آنها را هم می کشد.

Lossهای شبکه ها:

یک loss این شبکه ها crossentropy دو کلاسه هست  که مسئله باینری face-nonface را پوشش می دهد:

Loss box:

Loss box ها که یک مسئله regression است، در واقع فاصله تخمین تا حقیقت را محاسبه می کند که آیا مکان bounding box درست است یا خیر:

Loss landmarks: که باز هم مسئله regression است:

Loss کل شبکه که ترکیبی از هر سه loss می باشد.

درون کد اگر بخواهیم بررسی کنیم (mtcnn-test.py)

مقدار اول hyper parameter شبکه اول(p-net)

مقدار دوم hyper parameter شبکه دوم(R-net)

مقدار سوم hyper parameter شبکه سوم(O-net)

توسط detect_face.create_mtcnn سه شبکه pnet و rnet و onet را می سازیم.

یک clone از عکس های موجود در image_path می گیریم.

متد detect_face از detect_face را صدا میزنیم تا bounding box  و landmark ها را به عنوان خروجی بدهند.

که درواقع bounding box لیستی از چهارتایی های x,y,w,h و points لیستی از x,y های 5 تا  landmark داخل هر چهره است.