Speech Emotion Recognition

چکیده

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

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

مقدمه

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

تشخیص احساسات از روی گفتار 

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

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


مراحل انجام کار 

سیستم های تشخیص احساس از روی گفتار شامل 3 قسمت استخراج ویژگی ، انتخاب ویژگی و آموزش مدل می باشد .

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


جمع آوری داده 

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

مراحل آماده سازی داده ها 

برای آموزش مدل و تشخیص 4 کلاس گفته شده نیاز است تا مجموعه داده ی واحدی از لحاظ فرمت ، sampling rate ، bit resolution و تعداد کانال ( mono – stereo ) و … داشته باشیم .

بر این اساس داده های موجود را به شکلی واحد ، مطابق زیر درآوردیم :

  •  32 bit resolution
  •   16KHz sampling rate
  •  256kbps bitrate
  •  Mono audio chanells
  •   wav format

استفاده از سری دیتاست های مختلف (فرانسوی ، انگلیسی ، فرانسوی و انگلیسی ) 

به منظور دست یابی به بهترین کارایی ممکن با استفاده از داده های موجود در ابتدا تنها با استفاده از دیتاهای فرانسوی به آموزش مدل پرداختیم و به کارایی 96.2% و خطای 0.02 رسیدیم ، همین روند را برای دیتای انگلیسی پیش گرفتیم و نتایج 91.2% کارایی و 0.02 خطا مشاهده نمودیم . در آخر با استفاده از هردو سری دیتاهای انگلیسی و فرانسوی مدل را آموزش دادیم و به 92.7% و 0.006 رسیدیم .

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


استخراج ویژگی ها 

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

روش MFCC

در این پروژه از MFCC به عنوان ویژگی طیفی استفاده شده است. به منظور استخراج ویژگی، از ویژگیهای عروضی و طیفی بهره بردیم. ویژگی های عروضی شامل فرکانس ، گام و انرژی و ویژگی طیفی شامل خصوصیات MFCC است. فرکانس گام که از ارتعاش تارهای صوتی به وجود میآید حامل اطلاعات مهمی درباره ی احساس گوینده می باشد .

تحقیقات انجام شده نشان دهنده ی این هستند که روش استخراج ویژگی MFCC مناسب ترین روش برای سیگنال های صوتی به ویژه گفتار می باشند

MFCC مطابق روال زیر محاسبه می شود :

ورودی: یک فریم از سیگنال گفتار

1-  یک تابع پنجره ی مناسب مانند پنجره ی همینگ روی فریم های موجود اعمال می کنیم.

2- روی خروجی مرحله ی قبل تبدیل فوریه ی گسسته (DFT) اعمال می کنیم .

3- خروجی مرحله قبل را در یک بانک فیلتر که اصطلاحا بانک فیلتر mel نامیده می شود، ضرب می کنیم.

4- خروجی های مرحله ی قبل را با هم جمع می کنیم.

5- از حاصل جمع مرحله ی قبل لگاریتم می گیریم .

6- سپس با استفاده از تبدیل DCT یعنی Discrete cosine transform می گیریم .


معماری مدل های مورد استفاده 

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

 

سپس به پیاده سازی یک مدل با استفاده از Recurrent neural network پرداختیم و نتایجی بهتر مطابق قسمت قبلی رسیدیم .

 

با توجه به نتایج بدست آمده در این مرحله با مدل RNN پیش رفتیم و در انتهای لایه های موجود ،  با استفاده از Dense (چهار تایی)  و تابع فعال ساز Softmax به تفکیک 4 کلاس موجود پرداختیم .

در انتها موفق به تفکیک صداهایی در 4 احساس مختلف عصبانی ، خوشحال ، غمگین و خنثی شدیم .


پروژه ی تشخیص احساسات از روی گفتار                                                                                               محیا مهدیان _ نفیسه داوری

 

PixtoPix

PixToPix

در این بخش قصد داریم مدلی را پیاده سازی کنیم که با دادن یک تصویر به شبکه ، تصویری مشابه الگوهای زیر از شبکه بگیریم . برای مثال بتوانیم عکسی  در فضای آفتابی از یک منظره به شبکه بدهیم و تصویر همان منظره را در فضای ابری بخواهیم ، و یا اینکه عکس سیاه سفید از یک شی را به شبکه داده و عکس رنگی آن را از شبکه بگیریم ، و مثال هایی از این قبیل …

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

 

 

 

 

 

همانطور که در تصویر بالا مشاهده میکنید میتوانیم با داشتن لبه های یک کیف به تصویر اصلی کیف ، با داشتن منظره ای در هوای افتابی به آن منظره در هوای ابری و با داشتن segment های یک ساختمان به تصویری مشابه از یک ساختمان واقعی و با داشتن عکس سیاه سفید به عکس رنگی تصویرمان برسیم .

در اینجا می توانید نمونه های از این عملیات را به طور آنلاین مشاهده نمایید .


شبکه GAN

همانطور که می دانید در ساختار یک شبکه ی GAN دو واحد اصلی Genarator و Discriminator داریم ، که در واقع کار اصلی واحد Generator  تولید عکس های جعلی و به مرور  یادگیری تولید عکس های واقعی تر و شبیه تر به نمونه ی عکس های اصلی ، و وظیفه ی واحد Discriminator یادگیری فرایند تشخیص عکس جعلی از عکس واقعی می باشد .

به مرور هر دو شبکه ی Generator و Discriminator به ترتیب یاد میگیرند عکس های واقعی تر تولید و عکس های تقلبی را تشخیص دهند ( واحد Generator  سعی در فریب دادن واحد Descriminator دارد )  . پس بدین ترتیب ( همانظور که در بخش های قبلی دیدیم ) generator  یک نویز را به عنوان ورودی میگیرد و تصویری تولید میکند و Discriminator عکس تولیدی واحد Generator را گرفته و سعی در تشخیص جعلی بودن یا نبودن  آن دارد .

Conditional GAN :

conditional generative adverserial nets ها در واقع شبکه ها ی GAN  ای هستند که می توان با اضافه کردن یک ترم به Generator و  Discriminator  از شبکه بخواهیم آن چه مورد نظر ماست را تولید کند . برای مثال میتوانیم نویزی که قرار است به جنریتور بدهیم با یک one hot که عدد 3 را نشان می دهد concat کرده و به generator بدهیم تا برای مثال شبکه ای که دیتا ی Mnist را آموزش دیده بتواند عدد 3 را تولید کند یا برای مثال به طور پیشرفته تر از شبکه بخواهیم یک انسان که تصویرش را دریافت می کند ،  بتواند پیرتر کند .

بدین ترتیب اگر فرایند Train  را بدین گونه تغییر دهیم ( یک ترم اضافه به Discriminator  و Generator بدهیم ) میتوانیم آنچه گفته شد را پیاده سازی کنیم .

 


شبکه ی Generator :

در این بخش از یک auto encoder  برای پیاده سازی این شبکه استفاده میکنیم.

همانطور که میدانید auto encoder دارای یک سری لایه ی convlution در لایه های اول ( کوچک کردن طول و عرض و بزرگ کردن  عمق )  تا رسیدن به یک bottle neck ، و یک سری لایه ی TransposeConvolution ( بزرگ کردن طول و عرض و کوچک کردن  عمق ) تا رسیدن به سایز اولیه می باشد ، بدین صورت عکس ورودی را تا یک جایی کوچک کرده و سپس به ابعاد اولیه می رساند .

در شکل زیر نمونه ی این شبکه را مشاهده می نمایید :

همانطو که در تصویر بالا مشاهده می کنید ، ورودی شبکه ی Generator  یک عکس سیاه سفید بوده که این شبکه سعی در تولید عکس رنگی ( در مشابه ترین حالت ممکن به عکس رنگی اصلی در دیتاست) دارد .

ایده ای که در قسمت مطرح شد استفاده از skip connection های مشابه در شبکه ی Resnet بود ، به عبارتی از لایه ی n ام encoding به لایه n ام decoding یک skip connection با این هدف که ممکن است نیازی به طی کردن همه ی لایه های کانولوشن و به طبع تمام لایه های دی کانولوشن ( Transpose Convolution )  نباشد ، و با طی کردن تعداد کمتری از این لایه ها به هدف مربوطه برسیم ، بدین منظور ایده ای مطابق شکل زیر بیان گردید که به آن اصطلاحا UNet می گویند.


شبکه ی Discriminator :

این شبکه که وظیفه ی تشخیص دیتای واقعی ( دیتای موجود در دیتاست ) از دیتای غیر اصلی و جعلی ( تصویر تولید شده ی Generator )  را دارد ، ساختاری کانولوشنی مطابق شکل زیر داراست .

همانطور که مشاهده می کنید ورودی این واحد ، ورودی شبکه ( مثلا عکس سیاه سفید ) به علاوه عکس Unknown  ( دلیل Unknown  نامیدن این تصویر این است که نمیدانیم این عکس توسظ Generator تولید شده و یا تصویر اصلی رنگی ) می باشد .

پس بدین ترتیب شبکه ی Discriminator  سعی دارد با دریافت یک عکس سیاه سفید و یک عکس رنگی ( تولید شده ی Generator و یا عکس رنگی اصلی )  عکس های جعلی را از اصلی تشخیص دهد .

از آنجایی که این شبکه در خروجی یک تابع Sigmoid دارد و مقادیر بین 0 تا 1 برمیگرداند ، در واقع قضاوت سخت گیرانه ای دارد یعنی حتی اگر تنها یک پیکسل تفاوت مشاهده کند خروجی را نزدیک به 0 نشان می دهد ،از این رو میتوانیم در خروجی به جای داشتن یک سیگموید از یک ماتریس 30 در 30  در 1 استفاده کنیم ، که هر عدد در این ماتریس میتواند بین اعداد 0 و  1 باشد ( یعنی در واقع به جای یک سیگموید 30 در 30 عدد سیگموید داریم ) که هرعدد نزدیک به 1 و یا نزدیک به 0 در این ماتریس به ترتیب بیانگر مساوی بودن یا نبودن 70 پیکسل در تصویر مورد مقایسه است . به عبارت ساده تر اگر اولین عدد این ماتریس ( خانه ی سطر 1 و ستون 1 ) 0.9 باشد ، بیانگر یکسان بودن 70 پیکسل اول تصویر است. ( از آنجایی که 70 * 30 یعنی 2100 عددی بزرگتر از 256 که سایز تصویر ماست ، می باشد ، overlap نیز وجود خواهد داشت)


تعریف خطای شبکه ی Discriminator :

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

1) خطای ناشی از تشخیص نادرست دیتای اصلی به عنوان دیتای جعلی

2) خطای ناشی از تشخیص نادرست دیتای جعلی ( تولید شده ی Generator ) به عنوان دیتای اصلی .

اعمال این دو خطا را در شکل زیر میتوانید مشاهده نمایید .

 


تعریف خطای شبکه ی Generator

1) خطای ناشی از شکست در فریب دادن Discriminator :

با توجه به آنچه که گفته شد شبکه ی Generator باید بتواند عکس هایی تولید کند که شبکه ی Discriminator را فریب دهد ، به ظوری که شبکه ی Discriminator با گرفتن عکسی که Generator تولید می کند ،  لیبل True به معنای اصلی بودن عکس برگرداند ، پس برگرداندن هر چیزی جز 1 برای Generator  ، یک خطا محسوب می شود (چون در فریب دادن Discriminator  موفق نبوده ) و قابل انتشار در شبکه ی Generator برای به روز رسانی وزن های آن است .

2) خطای ناشی از تفاوت عکس تولید شده با عکس واقعی :

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

در شکل زیر فرایند اعمال دو خطای تعریف شده مشاهده میگردد :

 

Multi Label Classification

Multi Label Classification چیست ؟

می دانیم در  شبکه های کانولوشنی که دارای یک سری لایه ی میانی و لایه های ورودی و خروجی هستند ، در لایه های میانی اکثرا از Activation RELU  و در لایه ی خروجی از Activation  های Softmax  و Sigmoid   استفاده می شود.

Activation Sigmoid زمانی استفاده می شود که در لایه ی آخر 1 نورون داشته باشیم که نشان دهنده ی وجود دو کلاس است ، برای مثال زمانی که می خواهیم سگ را از گربه تشخیص دهیم از این تایع استفاده می کنیم که می توان 1 شدن آن را به منزله ی سگ بودن تصویر و 0 بودن آن را منزله ی گربه بودن تصویر در نظر گرفت .

Activation Softmax  زمانی استفاده می شود که بخواهیم بیش از 2 کلاس را تشخیص دهیم ، برای مثال وقتی میخواهیم 5 میوه را به شبکه آموزش دهیم در لایه ی آخر Activation Softmax را استفاده میکنیم که در واقع تبدیل Exponential عدد خروجی لایه ی آخر که مثلا میتواند به صورت اعداد 12- ، 10 ، 5 ، 2 و 6- باشد گرفته شده و با هم جمع میگردد و سپس هرکدام از این اعداد به این حاصل جمع تقسیم می شود ، که اعداد به دست آمده در بازه ی 0 تا 1 خواهند بود . عددی که بیشترین مقدار را داشته بیشترین مقدار را در این بازه خواهد داشت و عددی که کمترین مقدار را داشته کمترین مقدار را در این بازه خواهد داشت ، مثلا عدد 10 به معادل 0.95 میرسد و این نشان دهنده ی برنده بودن کلاس مربوط به این نورون خواهد بود .

اشکال توابع Sigmoid و RELU به این شکل می باشد :

اما تمام آنچه گفته شد مربوط به زمانی است که ما بخواهیم وجود یک Object  را تشخیص دهیم .

برای مثال در صورت داشتن یک عکس ماهواره ای که قصد داریم در آن تصویر وجود دریا و جنگل و … را بدانیم باید به شکل دیگری عمل کنیم ، و در واقع باید در لایه ی آخر نورون های مربوط به Object های موجود در تصویر True شده و نورون های مربوط به تصاویر غیر موجود در تصویر False شوند . به این نوع مسایل Multi Label Classification می گویند به عبات دیگر لایه ی اخر میتواند بیشتر از یک برنده داشته باشد و یا هیچ برنده ای نداشته باشد.


پیاده سازی Multi Label Classification در Keras :

برای پیاده سازی Multi Label Classification در Keras ابتدا کلاس های مورد نظر را import و پوشه ی دیتا ست مورد نظر را معرفی می کنیم.

 

 

Dataset مورد استفاده برای مساله ی مورد بررسی دارای پوشه هایی بدین شکل است که داخل هر کدام فولدر های Test  و Train  وجود دارند .

  • پوشه ی Black_jeans
  • پوشه ی Blue_jeans
  • پوشه ی Blue_shirt
  • پوشه ی Red_shirt

بدین ترتیب شبکه ی ما باید به شکلی بتواند تشخیص دهد که آیا در تصویر ورودی Jeans یا shirt  ویا رنگ آبی یا قرمز و یا مشکی وجود دارد یا خیر و چون در لایه ی اخر میتوانیم وجود بیش از یک Object را تشخیص دهیم ( آبی ، قرمز ، مشکی ، shirt و jeans ) این مساله ، مساله ی Multi Label Classification است . در واقع نورون های لایه ی اخر که هر کدام برای یکی از object های مورد نظر می باشند ،  باید به یک Sigmoid متصل شوند تا در صورت تشخیص آن شی در تصویر Fire  کنند.

مثلا در تصویر مقابل هم رنگ قرمز را داریم هم وجود Shirt پس باید در لایه ی اخر نورون های مربوط به رنگ قرمز و Shirt  که هرکدام به یک  Sigmoid  متصل هستند True شده و بقیه False شوند .

و یا اگر تصویر مقابل را که هیچ کدام از Object های shirt و jeans و red و blue و black در آن نیست به شبکه بدهیم در لایه ی آخر هیچ کدام از Sigmoid ها نباید Fire کنند.

همانطور که در کد زیر مشاهده مینمایید بعد از تنظیم مقدار Epochs  ، Learning Rate و Batch Size با استفاده از

میتوانیم تمام تصاویر موجود در دیتاست را در یک لیست به نام imagePaths  نگه  داریم . سپس آن را shuffle میکنیم تا عکس هایی که در یک پوشه بودند پشت هم قرار نگیرند.( دلیل اینکه از DataGenerator استفاده نمیکنیم این است که در Keras هر پوشه به منزله ی یک کلاس میباشد ولی در Multi Label Classification اینگونه نیست )

در مرحله ی بعد تمام عکس ها را خوانده و به سایز 96 در 96 ریسایز کرده و تابع mg_to_array را برایشان فراخانی می  کنیم، سپس آن ها را در لیست Data  میریزیم.

با استفاده از :

از کل آدرس پوشه ی در دیتا ست قسمت نام آن را برمی داریم ، سپس دو کلمه ی آن را از محل “_” جدا می کنیم و در یک لیست به نام Labels میریزیم.

در مرحبه بعد دیتا ها را نرمال می کنیم.

اگر لیست Labels را چاپ کنیم خواهیم دید که لیستی از دوتایی ها خواهد بود که این دوتایی ها نام پوشه هایی هستند که از محل “_” جدا کردیم .

بلاک کد بالا نتیجه ای بدین شکل خواهد داشت :

 

 

 

 

در قسمت بعد از کتابخانه ی scikit-learn استفاده کردیم و با استفاده از MultiLabelBinarizer هر کدام از دوتایی های لیست Labels را به حالت 0 , 1 درآوردیم تا بجای هر کلاسی که در آن بود مقدار 1 و به جای هر کلاسی که آن را وجود نداشت مقدار 0 را قرار دهیم ، به علاوه نام کلاس ها را چاپ کردیم:

اگر لیست Labels را بعد از این عملیات چاپ کنیم آن را به این شکل مشاهده میکنیم :

 

 

 

 

سپس کلاس های موجود را چاپ میکنیم:

 

با استفاده از قطعه کد زیر از کل دیتا های موجود 80 درصد آن را برای Train و 20 درصد آن را برای Test برمیداریم :

سپس عملیات Augmentation را روی دیتا های خوانده شده انجام میدهیم :

شبکه ای با معماری زیر میسازیم :

مشاهده می شود که در لایه ی اخر به تعداد کلاس ها نورون قرار میدهیم و هر کدام را به یک Sigmoid متصل می کنیم .

سپس Optimizer Adam را با تنظیم کردن Learning Rate و کم کردن آن در هر epoch ( با تقسیم کردن بر شماره  epoch ) ایجاد میکنیم :

در مرحله آخر مدل را Compile و نمودار های مربوط به Accuracy و Loss در Train Data و Test Dataرا رسم میکنیم میکنیم :

در آخر مدل را با پسوند h5 و Label ها را به صورت Pickle File  ذخیره میکنیم .( اگر با فرمت Pickle.dumps در فایل بنویسیم یک آبجکت پایتونی را مستقیما در یک فایل میریزد و اگر Load آن را صدا بزنیم همان آبجکت پایتونی را Load  میکند .)

 


استفاده از مدل Save شده :

در ابتدا کتابخانه های مورد نیاز را Import میکنیم :

سپس عکسی را از ورودی خوانده ، آن را resize  میکنیم و نمایش میدهیم :

سپس عکس را به سایز 96 در 96 resize و با تقسیم بر 255 آن را نرمال میکنیم ، به علاوه تابع img_to_array را فراخانی کرده و بعد با exapnd_dim یک dimension به آن اضافه میکنیم ( چون به صورت دیفالت با batch کار می کند و با اضافه کردن یک dimension ، انگار به آن یک batch میدهیم که در واقع در آن یک عکس بیشتر نداریم )

آدرس مدل و Label ها را که به صورت Pickle File ذخیره کرده بودیم  ، مشخص میکنیم .

سپس مدل و Label ها را Load میکنیم :

عکس مورد نظر را به مدل می دهیم و از بالاترین احتمالات دوتای اول آن را روی عکس چاپ میکنیم .

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

که خروجی مطابق زیر خواهد داشت :

 

 

 

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

 

عملیات مورفولوژی

Mathematical Morphology

دو عملیات اصلی در Mathematical Morphology وجود دارد :

  • Dilation ( انشعاب )
  • Erosion ( فرسایش – تحلیل )

همچنین یک سری عملیات ترکیبی نیز وجود دارد :

  • Opening and Closing
  • Thinning and Tickening
  • و ..

Dilation 

عمل Dilation تصویر باینری را بسط میدهد (Expand)  ، و همینطور علاوه بر گسترش دادن تصویر ، حفره های موجود در آن را از بین می برد و لبه های خراب را ترمیم می کند.

Erosion

عکس عملیات Dilation می باشد .
که تصویر باینری را تحلیل میدهد ، و در واقع تصویر را کوچک میکند و قسمت های اضافی را حذف می کند . ( Shrink )

 

برای انجام این عملیات به المان هایی از جمله شکلی به عنوان فیلتر نیاز داریم که دارای ناحیه ای است که به آن Origin می گوییم  ‌.

نمونه هایی از این فیلتر ها :

 

 

انجام عملیات Dilation 

ورودی این عملیات تصویر باینری B و فیلتر S هستند.

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

 

مثال متن باینری 

 

برای مثال براثر عمل Dilation روی متن باینری مقابل :

 

 

با استفاده از فیلتر  

 

تصویر حاصل بر اثر پر کردن حفره ها و نقاط خالی نوشته ، به این شکل در خواهد آمد :

 

 

مثال : بر اثر فرایند Dilation نتیجه عملیات به چه شکل خواهد بود ؟

 

انجام عملیات Erosion :

ورودی این عملیات تصویر باینری B و فیلتر S هستند.

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

 

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

 

عملیات های Opening و Closing  

این دو عملیات از مهم ترین فرایندها روی تصاویر باینری هستند.

Opening : عملیات حاصل از یک Erosion و سپس  Dilation .

نمونه هایی از عملیات Opening 

مثال ۱ :

مثال ۲ :

اگر با استفاده از فیلترِ دیسک ۱۱ پیکسلی عملیات opening را روی تصویر اولیه داشته باشیم ، در تصویر وسط روی عکس اولیه Threshold زده شده و سپس با انجام عملیات Opening میبینیم تصویر سمت راست نتیجه می شود که بدون کوچک شدن سایز تصویر نویز ها حذف شده اند ( ابتدا Erosion برای حذف نویز ها و سپس  Dilation برای برگرداندن تصویر به سایز اولیه ) .

Closing : عملیات حاصل از یک Dilation و سپس  Closing .

نمونه هایی از عملیات Closing

مثال ۱ :

مثال ۲ :

همینطور در تصویر بالا میبینیم در تصویر وسطی روی عکس اولیه Threshold زده شده و سپس در تصویر نهایی (سمت راست) نتیجه ی عملیات Closing را میبینیم که بدون بزرگ شدن سایز تصویر حفره ها پر شدند ( ابتدا Dilation برای پر کردن حفره ها و سپس  Erosion برای برگرداندن تصویر به سایز اولیه ) .

نمونه هایی از عملیات Opening – Closing 

همانطور که میبینیم با عملیات opening بدون کوچک شدن تصویر نویز ها حذف شده ، و سپس روی تصویر حاصل عملیات closing صورت گرفته و بدون بزرگ شدن تصویر حفره ها پر شده اند.

 

بررسی Opening-Closing و عملیات های Dilationو Erosion در OpenCv

برای انجام فرایند های Erosion و Dilation و Opening  و Closing در OpenCv میتوانیم به این شکل عمل کنیم :

 

با انجام این عملیات ها بر روی عکس مقابل :

 

 

نتایج بدین شکل خواهند بود  :

Erosion :

Dilation :

Opening :

Closing :

 

دستکاری تصاویر (۴) – عملیات ریاضی و ترکیب تصاویر رنگی در OpenCv

یادآوری چگونگی سر ریز شدن متغیر ها 

با توجه به اینکه برای تصاویر در OpenCV از نوع داده‌ای unit8 یعنی عدد صحیح بدون علامت ۸ بیتی استفاده میکنیم . پس این نوع ۳ به توان ۸ یعنی ۲۵۶ مقدار مختلف میتواند داشته باشد و مقادیر خارج از ۰ تا ۲۵۵ امکان پذیر نبود و در صورتی که عددی بزرگتر قرار نسبت داده شود متغیر سر ریز می‌شد.

به قطعه کد زیر توجه کنید.

در کد بالا ماتریس دو عنصری a که عناصر آن همه ۱ هستند ، بعد از اینکه عناصرش ۱۰۰ برابر میشوند و به علاوه ۲۵۵می شنود ماتریس [۲۵۵ ۲۵۵] ساخته میشود ولی بعد از افزایش به اندازه ی ۱۶۰ واحد در هر عنصر از ماتریس b ماتریس [۴ ۴] ساخته میشود چون سرریز صورت گرفته ( مقدار بیش از ۲۵۵) و دوباره مقدار مربوطه از ۰ شروع شده است .

خروجی کد فوق :

طبیعتا این موضوع برای جمع دو ماتریس هم اندازه نیز صادق است:

در کد بالا m1 و m2 دو ماتریس به ترتیب به مقادیر :

هستند.که بعد از عملیات جمع این دو ماتریس دو درایه ی سطر دوم به دلیل سرریز مقادیر ۰ و ۱ را میگیرند.

خروجی کد:

برای حل این مشکل ( خراب نشدن عناصر بر اثر overflow ) راه حل هایی از جمله راه حل زیر وجود دارد :

در کد مشاهده شده ماتریس m1 را داریم که می خواهیم مقدار را به تمام درایه های آن بیفزاییم . براثر این عملیات مقادیری از ماتریس اصلی که بیشتر از ۱۵۰ یا مساوی ۱۵۰ هستند وقتی با ۱۰۰ جمع شوند سر ریز میشوند . برای جلوگیری از این موضوع میتوانیم درایه هایی که مقدارشان بیشتر یا مساوی ۱۵۰ هستند برابر با بیشترین مقدار ممکن یعنی ۲۵۵ قرار داده و عملیات جمع را برای بقیه ی درایه ها انجام دهیم .

خروجی کد:

 

حل مشکل با  OpenCV :

اگر از توابع cv2.add و cv2.subtract استفاده کنیم این مشکل را مشاهده نخواهیم کرد و مقادیر کمتر از ۰ همان ۰ و مقادیر بیش از ۲۵۵ همان ۲۵۵ باقی خواهد ماند.
به کد مقابل توجه کنید :

در این قطعه کد تصویری را خواندیم و سپس ماتریسی با اندازه ی تصویر خوانده شده ساختیم که تمام عناصرش ۱۰۰ هستند ، سپس این ماتریس را با تصویرمان جمع کردیم و چون ازتابع add در opencv استفاده کردیم خرابی در تصویر نهایی مشاهده نشد ، و به طور مشابه عمل subtract را انجام دادیم .

تصویر Orginal  :

orginal

تصویر Add شده :

تصویر Subtract شده :

 

مثال عملی ترکیب تصاویر رنگی :

در این مثال عملی مشاهده میشود که بعد از خواندن دو تصویر رنگی با نام های img1 و img2 ، این دو تصویر را با استفاده از تابع add جمع کردیم و در تصویر نهایی از دست رفتگی بعضی پیکسل ها را داریم       ( همانطور که در زیر مشاهده میکنید مثلا تصویر img2 برخی قسمت هایش از دست رفته است).

 img1 :                                                        img1  img2 :
img2

result :

حل این مشکل با ترکیب دو تصویر با جمع وزن‌دار :

برای حل این مشکل میتوانیم با نسبت های مختلف ، مثلا  ۰.۵ و ۰.۵ یا ۰.۳ و ۰.۷  و یا…. نسبت هایی که مشابها جمعشان  ۱ گردد تصاویر را جمع کنیم .

تابع مورد نظر به شکل زیر می باشد :

addWeighted(src1, alpha, src2, beta, gamma)

که آلفا و بتا در فرمول دوم مشاهده میشود.

g(x)=(1−α)f0(x)+αf1(x)
dst=α⋅img1+β⋅img2+γ

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

 

 img1 :                                                        img1  img2 :
img2

result :

 

عملیات بیتی (Bitwise Operations) و نقاب‌گذاری تصویر (Masking) :

ابتدا به رسم یک مربع و نیم دایره برای پیاده سازی عملیات بیتی روی اشکال میپردازیم.

همانطور که قابل مشاهده است ، در صفحه ای به اندازه ی ۳۰۰ در ۳۰۰ که تمام عناصر ماتریس آن صفر هستند ( صفحه ی تمام سیاه ) یک مربع سفید در وسط صفحه از مختصات (۵۰ ، ۵۰) تا (۲۵۰ ، ۲۵۰) رسم میکنیم ، سپس در صفحه ای مشابه به رسم نیم دایره میپردازیم.

تصاویر به این شکل خواهند بود :

عملیات بیتی تصویر در OpenCV :

حال به بررسی ۴ عملیات

  • bitwise_and
  • bitwise_or
  • bitwise_xor
  • bitwise_not

روی تصاویر خواهیم پرداخت :

عملیات bitwise_and :

در نتیجه ی عملیات and بین دو تصویر قسمت هایی که پیکسل در هر دوی آن تصاویر ۱  ( سفید ) است ، سفید ( مقدار 1 ) باقی خواهد ماند ، و بقیه ی پیکسل ها صفر ( سیاه ) خواهند بود و نتیجه به این شکل خواهد بود :

عملیات bitwise_or :

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

عملیات bitwise_xor :

در نتیجه ی عملیات xor ، قسمت هایی از تصویر که مربع و نیم دایره تفاوت بیتی ( یکی صفر و دیگری یک ؛ یکی سیاه و دیگری سفید ) دارند ، سفید می شود.
نتیجه شکل زیر خواهد بود :

عملیات bitwise_not :

این تابع نیز قسمت هایی از تصویر که بیت ۰ دارند ۱ میکند و بلعکس ( پیکسل های سیاه را سفید میکند و پیکسل های سفید را سیاه )

مثال عملی با تصویر رنگی :

اگر تصویر گاو اصلی را crop کنیم و سپس با این تصویر  and کنیم :

با توجه به اینکه میدانیم هر چیزی که با ۱ ، and شود ، حاصل خود آن میشود ، و هرچیزی که با ۰ ، and شود حاصل ۰ خواهد بود پس در نتیجه تصویر به این شکل در خواهد آمد :

همانطور که مشاهده میشود  پیکسل هایی از تصویر گاو که در تناظر با قسمت های سیاه تصویر دایره هستند ، از بین خواهند رفت.(سیاه میشوند)

برای درک عملگر بیتی دو تصویر به مثال زیر توجه کنید :

خروجی به شکل زیر خواهد بود :