تشخیص لبخند در چهره – راهنمای کاربردی
در این مطلب به چگونگی تشخیص لبخند در چهره و در واقع تشخیص شادی در تصاویر با استفاده از «زبان برنامهنویسی پایتون» (Python Programming Language) پرداخته شده است. کسب و کارها همواره در تلاش هستند تا مهمترین محصول ممکن را برای مخاطبان خود ارائه دهند و این محصول چیزی نیست جز «شادی». اما چرا؟ شادی چیزی بیش از یک واکنش شیمیایی است. احتمال بازگشت یک مشتری خوشحال بیشتر است و دادههای مربوط به شادی میتوانند به کسب و کارها در درک اینکه کدام محصولات در شادسازی مشتریان عملکرد بهتری داشتهاند و در واقع «نرخ بقای» (Retention Rate) بالاتری را فراهم کردهاند، کمک قابل توجهی کنند. ماشینها میتوانند یاد بگیرند که شادی را تشخیص بدهند و در این راهنما، چگونگی ساخت یک مدل تشخیص چهره که امکان تشخیص لبخند (شادی) را دارد، آموزش داده شده است.
کار با پرداختن به مقدمات موضوع آغاز میشود. انسانها چگونه شادی را توصیف میکنند؟ شادی در چهره، معمولا از طریق چشمها و لبخند بیان میشود. به طور طبیعی، افراد وقتی لبخند را در چهره دیگران میبینند چنین استنباط میکنند که آن فرد شاد است. لبخند میتواند انواع گوناگونی داشته باشد، اما به طور کلی معمولا شبیه به یک U مسطحتر است. این «(:» خندانک تبسم است که نمایی مینیمالی از تبسم را ارائه میکند. در ادامه، از «الگوریتم ویولا-جونز» برای تشخیص لبخند در چهره (تشخیص شادی) استفاده شده است.
مواردی که در ادامه و برای ساخت شناساگر شادی استفاده شدهاند، عبارتند از:
در ادامه، از «اسپایدر» (Spyder) در آناکوندا استفاده شده است. اما مخاطبان میتوانند از «نوتبوک ژوپیتر» (Jupyter Notebook) نیز استفاده کنند. افرادی که از اسپایدر استفاده میکنند، باید صفحهای مانند آنچه در تصویر زیر آمده است را مشاهده کنند. همچنین، پیش از آغاز کد زدن باید اطمینان حاصل کنند که Haar Cascades را دانلود کرده باشند.
Haar Cascades
الگوریتم ویولا-جونز (Viola-Jones Algorithm) از ویژگیهای Haar مانند برای تشخیص ویژگیهای چهره استفاده میکند. Cascade مجموعهای از فیلترها است که یکی پس از دیگری برای تشخیص چهره از طریق ویژگیهای آن، بر تصویر اعمال میشوند.
این فیلترها در فایل XML خودشان در مخزن گیتهاب Haar Cascades [+] ذخیره شدهاند. برای ساخت شناساگر شادی، نیاز به سه فایل XML زیر است.
این موارد Cascadeهایی برای چهره، چشمها و لبخند هستند. باید هر یک از این ویژگیها در صورت شاد بودن تصویر وجود داشته باشند. کد به دست آمده از هر یک از لینکها را باید در ویرایشگر متن قرار داد و فایل را مطابق با اسامی بیان شده در بالا ذخیرهسازی کرد. هر سه فایل XML را باید در پوشه مشابهی ذخیره شوند که نوتبوک پایتون از آنجا باز میشود و کار خواهد کرد. حالا که Haar Cascades موجود است، باید به سراغ محیط مجازی رفت. اکنون، زمان کد زدن فرا رسیده است.
وارد کردن OpenCV و بارگذاری Cascadeها
1import cv2
2cascade_face = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
3cascade_eye = cv2.CascadeClassifier('haarcascade_eye.xml')
4cascade_smile = cv2.CascadeClassifier('haarcascade_smile.xml')
تنها کتابخانهای که باید «وارد» (Import) شود OpenCV است. با وجود آنکه این کتابخانه ابزار بسیار قدرتمندی برای تشخیص شی است، قدرتمندترین ابزار نیست. ابزارهای قدرتمندتر و جدیدتری نیز برای این کار ارائه شدهاند؛ اما OpenCV همچنان ارزشآفرین است و راهکار خوبی برای درک مبانی تشخیص شی محسوب میشود.
پس از وارد کردن (OpenCV (cv2، هر یک از Cascadeهای دانلود شده فراخوانی میشوند. بدین منظور، تنها نیاز به استفاده از تابع OpenCV به نام CascadeClassifier است.
تعریف تابع تشخیص روی چهره، چشمها و لبخند
1def detection(grayscale, img):
2 face = cascade_face.detectMultiScale(grayscale, 1.3, 5)
3 for (x_face, y_face, w_face, h_face) in face:
4 cv2.rectangle(img, (x_face, y_face), (x_face+w_face, y_face+h_face), (255, 130, 0), 2)
پیش از تعریف تابع تشخیص، باید این موضوع را دانست که این موارد بر یک تصویر تنها اعمال میشوند و سپس، با کنار هم قرارگیری همه تصاویر، نتیجه نهایی حاصل میشود. به دلیل آنکه الگوریتم ویولا جونز با تصاویر سیاه و سفید کار میکند، اولین آرگومان در این تابع روی grayscale (سیاه و سفید) تنظیم شده است. اگرچه، برای رنگی کردن تصویر نیاز به خروجی نهایی است؛ بنابراین آرگومان img برای تصویر نهایی قرار میگیرد.
سپس، نیاز به دریافت مختصات مستطیلی است که چهره را تشخیص میدهد. برای تعریف این مختصات، ۴ تاپل در نظر گرفته میشود: w ،y ،x و h. تاپلهای x و y مختصات گوشه چپ بالا هستند، در حالیکه w و h به ترتیب عرض و ارتفاع مستطیل محسوب میشوند. این تاپلها در متغیر face ذخیره میشوند و سپس از دیگر تابع OpenCV که به آن detectMultiScale گفته میشود برای گرفتن این مختصاتها استفاده میشود. بنابراین، از شی Cascade_face استفاده میشود و متد detectMultiScale با سه آرگومانی که در زیر بیان شدهاند روی آن اعمال میشوند:
- grayscale، زیرا تصویر در حالت سیاه و سفید تحلیل میشود.
- «عامل تغییر ابعاد» (Scale Factor) برابر با ۱٫۳ (اندازه تصویر به میزان 1.3x کاهش پیدا میکند)
- حداقل عدد مناطق همسایه پذیرفته شده: ۵ همسایه
سپس، برای ترسیم مستطیلها، یک حلقه for با ۴ تاپل h_face ،y_face ،x_face و w_face ساخته میشود. در حلقه For، از تابع rectangle استفاده شده است که از جمله دیگر توابع OpenCV محسوب میشود. این کار موجب ترسیم مستطیل روی چهره میشود و در این راستا، آرگومانهای زیر به آن داده شده است.
- «img» زیرا هدف ترسیم مستطیل روی تصویر اصلی (رنگی) است.
- مختصات گوشه سمت چپ بالا: x و y
- مختصات گوشه سمت چپ پایین: w و h
- رنگ مستطیل: در اینجا از یک رنگ مایل به آبی استفاده شده است.
- ضخامت لبههای مستطیل: در اینجا ضخامت ۲ انتخاب شده است (البته این انتخاب بدین معنا نیست که ۲ بهترین گزینه و انتخاب ممکن است).
توجه: کد زیر، در کد نهایی موجود در انتهای مطلب آمده است و در اینجا صرفا برای درک بهتر موضوع و به دلیل ارائه توضیحات پیرامون آن، آورده شده است.
1 ri_grayscale = grayscale[y_face:y_face+h_face, x_face:x_face + w_face]
2 ri_color = img[y_face:y_face+h_face, x_face:x_face+w_face]
اکنون که کار با چهره تمام شد، وقت تشخیص چشمها رسیده است. این تنها بخشی است که نیاز به مقداری ترفند دارد و درک آن سختتر است. اساسا، خطوطی که در بالا به آنها اشاره شده، باید برای چشمها در چهره وجود داشته باشند و بنابراین، چهره، «ناحیه مورد بررسی» (Region of Interest) محسوب میشود. به دلیل آنکه الگوریتم تنها با تصاویر سیاه و سفید کار میکند، آرگومان grayscale قرار داده میشود. اگرچه، نیاز به دریافت تصویر رنگی شده است، بنابراین آرگومان دیگری برای تصویر رنگی اضافه خواهد شد.
اساسا، ۲ منطقه مورد بررسی وجود دارد که در ادامه مورد بررسی قرار گرفتهاند. یک منطقه برای تصاویر سیاه و سفید و یک منطقه برای تصویر رنگی شده اصلی است. متعاقبا، ri_grayscale روی تصویر سیاه و سفید اصلی با طیفی از مختصاتهای مستطیل y:y+h و x:x+w قرار میگیرد. سپس، در تصویر رنگی، ri_color با مختصات مشابه مستطیلها ساخته میشود.
1 eye = cascade_eye.detectMultiScale(ri_grayscale, 1.2, 18)
2
3 for (x_eye, y_eye, w_eye, h_eye) in eye:
4 cv2.rectangle(ri_color,(x_eye, y_eye),(x_eye+w_eye, y_eye+h_eye), (0, 180, 60), 2)
سپس، یک حلقه for برای چشمها ساخته میشود. میتوان مورد قبلی را copy-paste کرد و رد این صورت تنها نیاز به تغییر نام تاپل و انتخاب یک رنگ متفاوت است.
1smile = cascade_smile.detectMultiScale(ri_grayscale, 1.7, 20)
2 for (x_smile, y_smile, w_smile, h_smile) in smile:
3 cv2.rectangle(ri_color,(x_smile, y_smile),(x_smile+w_smile, y_smile+h_smile), (255, 0, 130), 2)
4
5 return img
سپس، مجددا برای لبخند، مراحل مشابهی با آنچه برای چهره و چشمها انجام شد، صورت میپذیرد. هنگامی که از متد detectMultiScale استفاده میشود، از عامل مقیاس ۱٫۷ و حداقل همسایگی ۲۰ استفاده میشود (همانطور که پیش از این نیز بیان شد، برای درک این موضوع نیاز به کمی تجربه است). هنگامی که همه این کارها انجام شد، نیاز به فریم اصلی است.
نمایش خروجی در وبکم
1vc = cv2.VideoCapture(0)
2while True:
3 _, img = vc.read()
4 grayscale = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
5 final = detection(grayscale, img)
6 cv2.imshow('Video', final)
7 if cv2.waitKey(1) & 0xFF == ord('q'):
8 break
9vc.release()
10cv2.destroyAllWindows()
کار با ساخت یک شی که vc نامیده میشود و از کلاس VideoCapture از OpenCV استفاده میکند، آغاز شده است. این شی تنها آرگومانهای ۰ یا ۱ را میپذیرد. ۰ در صورتی که از وبکم داخلی و ۱ برای حالتی که از وبکم خارجی استفاده شود است. از آنجا که تابع تشخیص برای یک تصویر تنها کار میکند، اکنون باید حلقهای ساخته شود که این کار را در مجموعهای از تصاویر انجام دهد. بنابراین، از یک حلقه While نامتناهی استفاده میشود که با استفاده از تابع Break شکسته میشود. اکنون، خطوط بعدی ممکن است گیج کننده به نظر بیایند؛ اما اساسا، متد read از VideoCapture دو عنصر را دریافت میکند.
یکی از این عناصر آخرین فریمی است که از وبکم میآید. به دلیل آنکه کاربر تنها آن را میخواهد، باید img استفاده کرد، زیرا متد read تنها ۲ فریم را باز میگرداند و این تنها چیزی است که کاربر میخواهد. اکنون نیاز به فراخوانی این متد از کلاس VideoCapture است. از تابع cvtColor که تصاویر رنگی را به سیاه و سفید تبدیل میکند استفاده شده است؛ زیرا نیاز به یک چارچوب سیاه و سفید برای تشخیص تابع دارد. این تابع را grayscale نامیده و کلاس cvtColor دریافت میشود که میتواند ۲ آرگومان را دریافت کند.
- فریم (img)
- cv2.COLOR_BGR2GRAY (که میانگینی از Blue-green-red برای دریافت سایههای مناسبی از خاکستری است).
اکنون، متغیر جدیدی به نام final ساخته شده است؛ این متغیر، نتیجه تابع detect خواهد بود. با final، از تابع تشخیص با آرگومانهای grayscale و img استفاده میشود. تابع imshow تابع OpenCV دیگری است که این امکان را فراهم میکند که محتوای اصلی از وبکم و با یک انیمیشن مستطیل بیاید. این تابع تصاویر پردازش شده را به صورت متحرک شده نمایش میدهد. سپس، از تابع دیگری برای بستن پنجره در هنگامی که کار با آن تمام شده است، استفاده میشود.
همچنین، یک شرط if اعمال شده است که کاربر هر بار که دکمه q را روی کیبورد فشار دهد، برنامه کاربردی را متوقف میکند. این کار حلقه while را تا پایان فرایند میشکند. در نهایت، از متد release برای خاموش کردن وبکم و از تابع DestroyAllWindows برای متوقف کردن همه پنجرهها استفاده میشود. کد کامل مورد استفاده برای این کار، به منظور شفافیت هر چه بیشتر در ادامه ارسال شده است.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""
4Created on Wed Aug 7 13:43:51 2019
5@author: rohangupta
6"""
7
8import cv2
9
10cascade_face = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
11cascade_eye = cv2.CascadeClassifier('haarcascade_eye.xml')
12cascade_smile = cv2.CascadeClassifier('haarcascade_smile.xml')
13
14def detection(grayscale, img):
15 face = cascade_face.detectMultiScale(grayscale, 1.3, 5)
16 for (x_face, y_face, w_face, h_face) in face:
17 cv2.rectangle(img, (x_face, y_face), (x_face+w_face, y_face+h_face), (255, 130, 0), 2)
18 ri_grayscale = grayscale[y_face:y_face+h_face, x_face:x_face+w_face]
19 ri_color = img[y_face:y_face+h_face, x_face:x_face+w_face]
20 eye = cascade_eye.detectMultiScale(ri_grayscale, 1.2, 18)
21 for (x_eye, y_eye, w_eye, h_eye) in eye:
22 cv2.rectangle(ri_color,(x_eye, y_eye),(x_eye+w_eye, y_eye+h_eye), (0, 180, 60), 2)
23 smile = cascade_smile.detectMultiScale(ri_grayscale, 1.7, 20)
24 for (x_smile, y_smile, w_smile, h_smile) in smile:
25 cv2.rectangle(ri_color,(x_smile, y_smile),(x_smile+w_smile, y_smile+h_smile), (255, 0, 130), 2)
26 return img
27
28vc = cv2.VideoCapture(0)
29
30while True:
31 _, img = vc.read()
32 grayscale = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
33 final = detection(grayscale, img)
34 cv2.imshow('Video', final)
35 if cv2.waitKey(1) & 0xFF == ord('q'):
36 break
37
38vc.release()
39cv2.destroyAllWindows()
نتایج برنامه تشخیص لبخند در چهره
در ابتدا، به دلایل متعددی مدل به درستی کار نمیکرد. در واقع، مدل صورتهایی که تبسم نداشتند را نیز به عنوان چهره در حال تبسم در نظر میگرفت.
بنابراین عامل تغییر ابعاد و حداقل همسایهها مجددا بررسی شدند و تغییر کردند تا بهترین نتیجه حاصل شود.
اگر مطلب بالا برای شما مفید بوده، آموزشهای زیر نیز به شما پیشنهاد میشود:
- مجموعه آموزشهای دادهکاوی و یادگیری ماشین
- مجموعه آموزشهای دادهکاوی یا Data Mining در متلب
- مجموعه آموزشهای هوش مصنوعی
- زبان برنامهنویسی پایتون (Python) — از صفر تا صد
- یادگیری ماشین با پایتون — به زبان ساده
- آموزش یادگیری ماشین با مثالهای کاربردی — مجموعه مقالات جامع وبلاگ فرادرس
^^
سلام خوبین شما ، ممنون از اطلاعاتی ک در اختیار ما میزارین ، ببخشین یه سوال دارم ، اینکه فایل های xml که برای این کلاسیفایر استفاده میشن ، توسط sql باید نوشته بشن ؟ ممنون میشم راهنمایی کنین