مقدمه‌ای بر شبکه‌های عصبی(2)

تا اینجا به دو مبحث درباره شبکه های عصبی پرداختیم. Activation function  برای تعیین عملکرد تابع خروجی و cost function  برای تعیین عملکرد بد شبکه. و برای بهبود عملکرد تابع مسائل بهینه سازی مطرح شد (مشتقات جزئی). اکنون به مسئله یادگیری(learning) شبکه میپردازیم.

Gradient Descent and Back-propagation

Gradient Descent

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

مثال : در این مسئله یک متغیر(w) داریم. و C  ، cost function  است.

یک وزن رندوم انتخاب میکنیم و مشتق c را نسبت به w محاسبه میکنیم. در نتیجه شیب به دست می آید. که جهت آن از روی علامتش مشخص می شود.

w را به سمت جهتی که به دست آوردیم، حرکت می دهیم. که در اینجا سمت راست است. یعنی باید w را بیشتر کنیم.

که با تکرار این کار در نهایت مقدار cost ، مینیمم می شود. در این نقطه مشتق یا شیب برابر با 0 است. با رسیدن به این مرحله نقطه بهینه پیدا می شود.

همان طور که دیدیم، پیدا کردن مینیمم برای فضای دو بعدی ساده بود. اما در فضاهای n بعدی این کار ساده نخواهد بود. و با شکل های پیچیده تری مواجه خواهیم شد.

پس با استفاده از gradient descent  میتوانیم بهترین پارامتر برای مینیمم کردن cost را به دست آوریم. برای مثال پیدا کردن بهترین مقادیر برای انتخاب وزن نورون های ورودی.

 

Backpropagation 

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

تابع cross entropy

one hot encoded

قبلا دیدیم که در شبکه تعدادی label  داشتیم. برای نشان دادن داده ی مربوط به آن label  به جای نشان دادن داده ، آن را به صورت one hot encoded  نمایش می دهیم. یعنی به تعداد کلاس های موجود 0 میگذاریم و عدد مربوط به کلاس را 1 میکنیم. یعنی به این شکل:

 

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

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

Cross entropy 

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

Tensorflow playground

Tensorflow playground یک visualization  برای آزمایش شبکه های عصبی است که از طرف سایت tensorflow  اراائه شده است. که میتوان در آن با data های مختلف شبکه را train کرد. میتوان برای شبکه به تعداد دلخواه hidden layer و نورون اضافه کرد. وزن ها نیز به صورت رندوم تعیین شده اند که قابل مشاهده و تغییر اند.

در قسمت بالای صفحه چند آیتم وجود دارد.

1.epoch: تعداد به روز رسانی های شبکه به ازای بررسی همه ی data ها را مشخص میکند.

2.learning rate

3.activation: نوع activation function را مشخص میکند که میتواند linear، sigmoid،tanh  یا relu باشد.

4.regularization: برای مینیمم کردن تابع cost، مجموع توان 2 تمام وزن ها و بایاس ها را محاسبه میکند و مقادیر آنها را محدود میکند تا خیلی بزرگ نباشند تا یک وزن زیاد نتواند تاثیر زیادی روی شبکه داشته باشد و قدرت بین شبکه تقسیم شود و داده را حفظ نکند. میتواند مقادیر none، L1 یا L2 را داشته باشد.

5.regularization rate

6.problem type: نوع الگوریتم را مشخص میکند که classification باشد یا regression.

در قسمت چپ صفحه نیز چند آیتم وجود دارد.

1.data: از این قسمت میتوان از بین انواع dataset های موجود یکی را انتخاب کرد که میزان سختی آن ها متفاوت است.

2.ratio of training to test data: نسبت دیتاهای test و train را مشخص میکند.

3.noise: میزان noise موجود در دیتا را مشخص میکند. که هرچه بالاتر باشد، نشان دهنده ی در هم آمیختن بیشتر data ها است.

4.batch size: تعداد داده هایی را مشخص میکند که شبکه بعد از بررسی آنها، عملیات optimization  را اجرا میکند.

مقدمه ای بر یادگیری ماشین (Machine Learning)

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

برخی از روش های یادگیری ماشین

الگوریتم های یادگیری ماشین اغلب به عنوان نظارت شده یا نظارت نشده و تقویتی دسته بندی می شوند.

1.یادگیری نظارت شده یا Supervised Learning :

الگوریتم های یادگیری ماشین تحت نظارت می توانند آنچه را که در گذشته آموخته شده است به منظور پیش بینی رویدادهای آینده با استفاده از مثال های برچسب گذاری شده برای داده های جدید اعمال کنند. با شروع فرایند تجزیه و تحلیل یک مجموعه داده‌ شناخته شده، الگوریتم یادگیری، یک تابع انتزاعی برای پیش بینی مقادیر خروجی تولید می کند. سیستم می تواند اهداف هر ورودی جدید را پس از آموزش کافی فراهم کند. الگوریتم یادگیری همچنین می تواند خروجی خود را با خروجی صحیحِ در نظر گرفته شده مقایسه کرده و به منظور تغییر مدل، خطای خود را پیدا کند. مسایل این روش به دو دسته Classification و Regression تقسیم بندی می شوند که در مسایل Regression متغیر خروجی مقادیر پیوسته را می گیرد و بیشتر این مسایل به تخمین زدن یا پیش بینی یک پاسخ مربوط است ولی در مسایل Classification متغیر خروجی کلاسی از برچسب ها (Labels) را می گیرد و بیشتر به تشخیص این که داده ها به کدام گروه ها یا کلاس ها تعلق دارند، می پردازد.

 

2.یادگیری بدون نظارت یا Unsupervised Learning :

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

 

 

3.یادگیری تقویتی یا Reinforcement Learning :

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

استفاده از وبکم در OpenCV

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

به وسیله تابع ()VideoCapture وبکم را راه اندازی می کنیم که خروجی آن یک شی (object)  می باشد که در اینجا آن را در متغیر cap قرار داده ایم.

این شئ یک متد به نام ()read دارد که با فراخوانی آن وبکم فعال می شود و شروع به دریافت فریم ها از وبکم می‌کند.

خروجی تابع ()read نوع داده ای tuple در پایتون است که در اینجا آن را در متغیرهای frame و ret ذخیره کرده ایم.

frame همان تصاویر دریافتی از وبکم است و چیزی که در ret ذخیره شده یک boolean است که نشان می دهد که آیا عملیات موفق آمیز بوده یا نه.

به وسیله تابع ()cap.release هم می توان وبکم را آزاد کرده و در نتیجه وبکم خاموش می‌شود.

به کد زیر دقت کنید:

قاعدتا میتوان روی تصاویری که از وبکم دریافت میکنیم قبل از نمایش تغییراتی ایجاد کنیم. به دو مثال زیر دقت کنید.

مثال 1) نمایش در وبکم به صورت آینه ای یا برعکس (flip)

یادآوری:

تصویر اصلی

چرخش عمودی یا Vertical Flip

چرخش افقی یا Horizontal Flip

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

  • اگر صفر باشد: به صورت عمودی تصاویر را flip می کند.
  • اگر مثبت باشد:به صورت افقی تصاویر را flip می کند.
  • اگر منفی باشد:به صورت هم عمودی و هم افقی تصاویر را flip می کند.

 

مثال 2) نمایش تک کاناله با وبکم

در این کد ابتدا به اندازه طول و عرض فریم یک ماتریس با مقادیر صفر می سازیم سپس هر کانال رنگی که از وبکم دریافت می شود را جدا می کنیم و در نهایت هر کانال را به صورت جداگانه نمایش می دهیم؛ به این صورت که با تابع ()cv2.merge فقط همان کانال رنگی و به جای دو کانال دیگر همان ماتریس صفری که ساخته بودیم را به عنوان ورودی می دهیم.

 

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

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 :

 

دستکاری تصاویر (۶) – فیتلرها در Open CV و حذف نویز تصاویر

در قسمت قبلی با کرنل‌ها و نحوه کارکرد آن‌ها و استفاده از آنها برای ایجاد فیلتر روی تصاویر آشنا شدیم؛ حال با اعمال فیلتر روی تصاویر با استفاده از کتابخانه Open CV و توابع مربوطه آشنا می‌شویم.

اعمال فیلتر‌های دو بعدی رو تصویر

با استفاده از Open CV اعمال فیلتر‌های دو بعدی توسط کرنل بر روی تصاویر توسط تابع زیر انجام می‌شود:

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

فیلتر محوی (Blur Filter)

همانطور که در پست قبل دیدیم برای محو کردن تصویر می‌توانیم یک کرنل Moving Average را بر روی تصویر اعمال کنیم. این کرنل یک ماتریس با مجموع جملات ۱ است و هرچه کرنل بزرگ‌تر باشد میزان تاری تصویر بیشتر خواهد شد.

کرنلی که در دفعه قسمت اول برای تاری استفاده شده است یک ماتریس ۳*۳ با عناصر ۱ است که از آنجا که مجموع عناصر ماتریس باید ۱ باشد تقسیم بر ۹ شده است. همچنین برای قسمت دوم از ماتریس بزرگتر ۵*۵ استفاده شده و تقسیم بر ۲۵ شده است.

برای اعمال فیلتر Blur می‌تواند از تابع اختصاصی زیر نیز استفاده کرد:

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

دیگر فیلتر‌های Blur

در Open CV علاوه بر کرنل Box (کرنل Moving Average مورد استفاده تا الان) برای محو کردن تصویر لکرنل‌های گوسین (Gaussian)، مدین (Median) و دوجانبه (Bilateral) نیز پشتیبانی می‌شوند.

فیلتر Gaussian Blur

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

فیلتر Median Blur

این فیلتر متوسط مقدار پیکسل‌هایی که درون کرنل قرار می‌گیرند را به عنوان مقدار نهایی پیکسل قرار می‌دهد.

فیلتر Bilateral Blur

این فیلتر سعی می‌کند درحالی که تصویر را محو می‌کند لبه‌های تصویر را تیز و دست نخورده نگاه دارد. به دلیل همین ویژگی این فیلتر در حذف نویز کاربرد زیادی دارد.

 

حذف نویز تصویر

برای حذف نویز تصویر می‌توان از تابع زیر که از روش میانگین گیری استفاده می‌کند کمک گرفت:

پارامتر‌های تابع عبارت‌اند از:

  • src : عکس مورد نظر برای حذف نویز
  • dst : متغیری برای ذخیره کردن عکس خروجی – با دادن none به این پارامتر، خروجی تابع عکس خروجی خواهد بود.
  • h : این پارامتر قدرت فیلتر را برای میزان شدت نور تنظیم می‌کند. هرچه مقدار این پارامتر بزرگتر باشد علاوع بر حذف نویز ممکن است از جزئیات تصویر نیز بکاهد و هرچه کوچکتر باشد جزئیات تصویر را نمی‌کاهد اما ممکن است نویزها را به درستی کاهش ندهد (بازه ۵ تا ۱۰ برای این پارامتر مناسب است).
  • hcolor : همانند h برای مولفه‌های رنگی
  • templateWindowSize : سایز گیره محاسبه کننده وزن‌ها (باید عددی فرد باشد).
  • searchWindowSize : سایز کرنل محاسبه کننده میانگین وزن‌دار برای هر پیکسل (باید عددی فرد باشد).

 

بر اساس نوع تصویر چهار تابع محتلف برای کاهش نویز توسط روش میانگین گیری وجود دارد

  • ()cv2.fastNlMeansDenoising : یا یک تصویر Grayscale کار می‌کند.
  • ()cv2.fastNlMeansDenoisingColored : با یک تصویر رنگی کار می‌کند.
  • ()cv2.fastNlMeansDenoisingMulti : با رشته‌ای از عکس‌های Grayscale که با فاصله زمانی کم گرفته شده‌اند کار می‌کند.
  • ()cv2.fastNlMeansDenoisingColoredMulti : مانند قبلی برای عکس‌های رنگی.

دستکاری تصاویر (۵) – فیلترها و کرنل‌ها

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

برای شروع به چند تعریف نیاز داریم:

تصویر

همانطور که می‌دانید تصویر یک ماتریس است که در هر خانه مقادیر رنگ آن خانه (با توجه به سیستم رنگی مورد استفاده) قرارگرفته اند.

کانولوشن (Convolution)

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

کراس‌کرولیشن (Cross-correlation)

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

 

در پردازش تصاویر، توابع ما درواقع ماتریس‌های تصاویر هستند. به ماتریس عبوری (اعمال شده) به تصویر کرنل می‌گوییم. همچنین در پردازش تصاویر (در عموم کتابخانه‌‌های مطرح و همینطور Open CV) از عملیات کراس‌کرولیشین استفاده می‌شود.

کرنل

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

 

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

اعمال کرنل روی تصویر

 

در اعمال کرنل روی تصویر نیاز داریم تا با عبور کرنل بر روی تصویر و انجام عملیات کراس‌کرولیشن نتیجه عملیات در خانه‌ای از خانه‌‌های کرنل (که روی تصویر قرار‌گرفته اند) نگاشته شود. برای این‌کار عموما خانه وسط ماتریس کرنل را در نظر می‌گیرند؛ درنتیجه عموم کرنل‌های مورد استفاده ماتریس‌هایی فرد-فرد هستند.

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

  • کانولوشن بدون حاشیه‌گذاری (Valid Padding Convolution)
    عبور کرنل به صورتی که خانه اول ماتریس کرنل (خانه [۰.۰]) بر روی خانه اول ماتریس تصویر بیافتد و کرنل از تصویر خارج نشود.
    این روش باعث از دست رفتن قسمت‌هایی از حاشیه تصویر می‌شود.
نحوه عبور یک ماتریس کرنل بر روی یک ماتریس تصویر و انجام عملیات کراس‌کرولیشن
نحوه عبور کرنل روی ماتریس تصویر و انجام عملیات کراس‌کرولیشن در حالت Valid Padding

 

  • کانولوشن با حاشیه‌گذاری (Same Padding Convolution)
    عبور کرنل به صورتی که خانه مرکز کرنل (خانه‌ای که برای نوشتن مقادیر عملیات در هر مرحله انتخاب شده) بر روی خانه اول ماتریس تصویر بیافتد.
    در این حالت کرنل می‌تواند از تصویر خارج شود که مقادیر خارج از تصویر عموما صفر در نظر گرفته می‌شوند.
نحوه عبور کرنل روی ماتریس تصویر و انجام عملیات کراس‌کرولیشن در حالت Same Padding

توجه کنید که در تصویر بالا حرکت کرنل بیشتر از یک پیکسل است؛ برای همین تصویر خروجی از ورودی کوچکتر شده است.

 

به جز دو روش فوق برای جلوگیری از کوچک شدن تصویر می‌توان از روش‌های تکرار حاشیه تصویر (Edge Value Replication) و یا گسترش آینه‌وار (Mirror Extension) نیز استفاده کرد:

از راست به چپ: گسترش آینه‌وار، تکرار حاشیه تصویر و حاشیه‌گذاری

استفاده از کرنل‌ها

چند مثال از کرنل‌ها با فرض اینکه خانه وسط هر کرنل برای نوشتن مقادیر استفاده شود و همچنین خانه وسط بر روی هر پیکسل قرارگیرد و کرنل در هر مرحله یک پیکسل جابه‌جا شود :

کرنل تطابق

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

کرنل انتقال به چپ

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

 

 

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

استفاده از کرنل‌ها برای ایجاد فیلتر روی تصاویر

فیلتر محوی (Blur Filter)

با عبور یک کرنل Moving Average (کرنل تصویر پایین) که کرنلی با مجموع مقادیر ۱ است و مقدار هر خانه را با میانگین مقدار خانه‌های همسایه‌اش جایگذین می‌کند، می‌توان تصویر را محو کرد.

 

این کرنل تغییرات ناگهانی در رنگ تصویر را ملایم‌تر می‌کند. به تصویر زیر که عبور کرنل بالا بر روی یک ماتریس است دقت کنید:

 

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

 

فیلتر تیزی (Sharpen Filter)

کرنل زیر را در نظر بگیرید:

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

ماتریس سمت راست همان کرنل مربوط به فیلتر محوی (Blur) است که تصویر را بدون جزئیات تولید می‌کند؛ با تفریق این ماتریس از خود تصویر (ماتریس وسط) جزئیات تصویر اصلی حاصل می‌شود؛ حال با اضافه کردن این ماتریس به خود تصویر می‌توان جزئیات تصویر را به آن افزود و تصویری با جزئیات نمایان‌تر شده تولید کرد.

نتیجه حاصل از جدا کردن جزئیات و اضافه کردن آن به عکس را می‌توان به ترتیب در سطر‌های تصویر زیر مشاهده کرد:

درنتیجه فیلتر تیزی (Sharpen Filter) به صورت زیر است:

 

دستکاری تصاویر (۴) – عملیات ریاضی و ترکیب تصاویر رنگی در 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 شود حاصل ۰ خواهد بود پس در نتیجه تصویر به این شکل در خواهد آمد :

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

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

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

دستکاری تصویر (3) – مثال‌های عملی در OpenCV

تبدیلات همگن (Affine Transform) 

انتقال (Translation) :

برای پیاده سازی این تبدیلات  از cv2.warpAffine استفاده میکینم.

به طور مثال در کد زیر :

پس از خواندن عکس  و دریافت عرض و طول تصویر:

یک نسبت دلخواه برای انتقال طول و عرض تصویر در نظر گرفتیم :

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

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

چرخاندن  (Rotations) :

*یادآوری

ماتریس دوران:

 

 

 

دوران در opencv

  • از نقص های این روش میتوان به ایجاد فضاهای سیاه اطراف تصویر اشاره کرد که در ادامه فضاهای سیاه ایجاد شده اطراف تصویر را با کراپ از بین میبریم.

روشی دیگر برای دوران :

ترانهاده ماتریس

ماتریس ترانهاده  با تغییر جای سطر ها با ستون ها باعث چرخش تصویر میشود و فضای سیاه اطراف تصویر ایجاد نمی کند .

flip  تصویر

تصویر را در جهت افق و خط عمود آینه می کند.

پارامتر دوم :

صفر یا false عکس را حول محور x  ها قرینه میکند.

یک یا True عکس را حول محور y ها قرینه میکند.

تغییر اندازه (scaling, resizing) و درون‌یابی (interpolations)

  • fx  و fy  پارامتر های  نام دار هستند میتوان آنها را به تابع پاس نداد.

روش های درون یابی :

  1.  Bilinear Interpolation (درج وابسته به ۴ پیکسل ۴ طرف)
  2.  Bicubic interpolation (درج وابسته به ۴ پیکسل ۴ طرف به علاوه ۴ پیکسل اریب)
  3.  Nearest Neighbor (نزدیکترین همسایه)

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

جهت هایی را که میخواهیم  scale شوند را در قطر ماتریس قرار میدهیم.

معایب :

  1. مشکل سیاهی تصویر را دارد.
  2. عکس بعد از اعمال interpolations باید crop شود .

Image Pyramids

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

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

کاربرد: آموزش به هوش مصنوعی برای تشخیص اشیاء

Cropping

Opencv تابع مشخص برای کراپ کردن ندارد.

روش های جایگزین :

یکی از روش های کراپ کردن slicing است که با دادن بازه ی دقیقی از  x ,y (برای ساده تر شدن عکس را بصورت دو بعدی و سیاه سفید تصور میکنیم)همان بازه ی مشخص شده را کراپ می کنیم.

نکات :

مختصات شروع و پایان حتما  باید اعداد صحیح باشند.

در بازه نویسی به صورت   [ x1 : x2 , y1:y2 ] :

x1 شامل بازه میشود اما x2 نوشته نمیشود .

روش دیگر اسلایس کردن ماتریس  ها به کمک  numpy است.

مثال:

a=np.array([[100,200,400],[1,2,3]])

میخواهیم  عناصر سطر اول [0] و ستون دوم [1]  را انتخاب کنیم.

a [0: , 1:] => array([[200, 400],[ 2, 3]])

 

دستکاری تصویر (2) – دوران، انتقال، مقیاس و درون‌یابی

Rotation (دوران)

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

تابعی که در opencv برای این کار گمارده شده است به صورت زیر است:

 

که آرگومان اول و دوم به ترتیب x و y مرکز دوران را میگیرند و آرگومان بعدی زاویه چرخش و آرگومان اخر آپشن اضافه ای در اختیار ما قرار داده است و عددی برای بزرگنمایی یا کوچک نمایی تصویر میگیرد و بدون درگیر کردن ما با ماتریس چرخش و سینوس و کسینوس این تبدیل را به خوبی انجام میدهد.=)

خروجی این تابع؛ ماتریس چرخش یا دوران می باشد.که میتوان با تابع پرینت آن را نمایش داد.

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

 

2D Translation (انتقال دوبعدی)

برای انتقال یک نقطه از مکانی به مکان دیگر از ماتریس زیر استفاده میکنیم:

که در اینجا:

x´ = x + Tx = 1 * x + 0 * y + Tx

y´ = y + Ty =  0 * x + 1 * y + Ty

و به این صورت میتوانیم تصویر را جابجا کنیم.

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

1 ها مقدار مقیاس گذاری را مشخص میکنند یعنی 1 خانه ی (0 و 0) نشان دهنده scale در راستای ایکس و 1 خانه ی (1 و 1) نشان دهنده scale  در راستای ایگرگ میباشد.که چون در اینجا مقادیر 1 هستند یعنی اندازه ی تصویر بدون تغییر میماند  و بزرگ نمایی یا کوچک نمایی انجام نمیشود.

تابعی که برای این کار در opencv در نظر گرفته اند بدین صورت است:

 

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

و خود ماتریس انتقال را میتوانیم بدین صورت بسازیم:

Np.float32([[1 , 0 , tx] , [0 , 1 , ty]])

Scalling (مقیاس گذاری)

ما اگر بخواهیم مثلا یک ماتریس 2 در 2 را به ماتریس 6 در 6 تبدیل کنیم یک سری نقاط(پیکسل) را نداریم.

با این 4 روش میخواهیم این نقاط را بسازیم.

  1.  Nearest Neighbor (نزدیکترین همسایه)
  2.  Bilinear Interpolation (درج وابسته به ۴ پیکسل ۴ طرف)
  3. Bicubic interpolation  (درج وابسته به ۴ پیکسل ۴ طرف به علاوه ۴ پیکسل اریب)
  4. استفاده از ماتریس تغییر شکل (با استفاده از تابع warpaffine با ارقام دلخواه و ترتیب گفته شده در ماتریس scalling، که در ابتدا آمده است)

این مقیاس گذاری دو حالت دارد:

  • بزرگ نمایی
  • کوچک نمایی

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

در این روش مثلا فلان پیکسل را نسبت می بندیم که آن روی یک پیکسل متناظرش در ماتریس جدید می افتد پس همان مقدار پیکسل را به آن میدهیم.سپس پیکسل دیگری را بررسی میکنیم که مثلا هیچ پیکسلی را متناظرش در ماتریس جدید نمی یابیم و در آن پیکسل مقدار نزدیکترین پیکسل را قرار می دهیم.

روش درج وابسته به۴ پیکسل ۴ طرف:نسبت به روش قبلی دقیقتر است.همانطور که مشخص است مقادیر 4 پیکسل اطراف را میانگین گرفته و پیکسل های خالی را پر میکنیم.

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

حال میخواهیم تابعی در opencvکه این کار را انجام میدهد بیان کنیم:

 

آرگومان اول تصویر مورد نظر است.آرگومان بعدی سایز عکس خروجی ست و دو آرگومان بعدی مقدار یا درصد مقیاس گذاری را مشخص میکند.(مثلا اگر عدد ۲ را به هردو آنها پاس دهیم یعنی میخواهیم تصویر در راستای طول و عرض ۲ برابر شود) و آرگومان اخر روش مقیاس گذاری(که در بالا توضیح دادیم) را تعیین میکند.خروجی این تابع نیز تصویر scale شده میباشد.

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

در آخر مقایسه انواع  روش های scaleرا باهم میبینیم:

دستکاری تصویر (1) – ماتریس‌های تبدیل

در جلسات قبل با مفهوم فضاهای رنگی آشنا شدیم و خواندیم که هر عکس رنگی از سه کانال رنگی (R,G,B) تشکیل شده است که هر کدام می توانند از صفر تا 255 مقدار بگیرند .

و اگر ما دستور image.shape  را برای یک عکس رنگی چاپ کنیم خروجی اینچنین خواهد بود

(height,width,3)

که عدد 3 نشان دهنده ی وجود هر سه کانال رنگی قرمز، سبز و آبی است اما اگر عکس را در حالت سایه و سفید (gray scale) ببریم خروجی دستور تنها طول و عرض عکس خواهد بود و دیگر تنها یک کانال رنگی وجود دارد که به صورت باینری است و صفر نشان دهنده ی نبود رنگ و 1 بیش ترین مقدار وجود رنگ را نشان میدهد(صفر نشان دهنده رنگ سیاه و یک نشان دهنده ی رنگ سفید است).

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

 

که خروجی آن برای هر کانال به صورت زیر خواهد بود:

 

 

تا اینجای کار با مفاهیم اولیه ی open cv  آشنا شدیم اکنون میخواهیم وارد مبحت image manipulations بشیم که لازمه ای این مبحث این هستش که یه دوره ی سریعی روی مباحث جبر خطی که عمدتا در هندسه تحلیلی عنوان شده داشته باشیم .

انواع روش های image manipulations  یا دستکاری تصویر:

  • انتقال های همگن یا غیر همگن ( (Transformations, affine and non affine
  • تبدیلات (Translations)
  • Rotations (دوران)
  • Scaling, re-sizing and interpolations  ( درون یابی یا interpolations به معنای این است که در هنگام تغییر سایز عکس پیکسل هایی که خالی میماند را با چه الگوریتمی میخواهیم پر کنیم.)
  • Image Pyramids

انتقال

Transformations ها کلا تبدیلات ماتریسی هستند که عموما به صورت ضرب دو ماتریس هستند که ماتریس سومی را به عنوان خروجی میدهند و به دو نوع کلی همگن یا غیر همگن تقسیم میشوند.

تبدیلات همگن

تبدیل همگن یا تبدیل آفین یا transformation Affine نوعی تبدیل ریاضی است که خطی بودن و نسبت فاصله ها در آن حفظ می شود.(خطوطی که موازی بودند پس از تبدیل هم حتما موازی باقی میمانند اما طول و زاویه ی بین خطوط لزوما حفظ نمیشود).

بدین ترتیب در نتیجه یک تبدیل همگن، تمامی نقاط روی یک خط در ورودی، در خروجی نیز روی یک خط خواهند ماند.

  • انتقال، تجانس، تشابه و چرخش نمونه هایی از تبدیل های همگن هستند.

نکته هر تبدیل خطی همگن هست اما هر تبدیل همگنی خطی نیست.

 

معرفی وکتور

یک بردار یک بعدی است. که دو نوع دارد وکتور ستونی و سطری:

1)وکتور ستونی    2) وکتور سطری

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

نحوه محاسبه نرم اقلیدسی:

اگر دو وکتور به نام های A,B  داشته باشیم نرم اقلیدسی آن برابر است با

ماتریس

ماتریس همان بردار mxn است که در برنامه نویسی نیز همین معنا را دارد و یک عکس سیاه و سفید درواقع یک ماتریس  است که به میزان عرض عکس سطر و ارتفاع آن ستون دارد و هر درایه نمایانگر یک پیکسل است که میتواند ازصفر تا 255 مقدار بگیرد.

عکس رنگی نیز در واقع شامل سه ماتریس است که هر کدام از آنها مقدار یکی از کانالهای رنگی را نگه میدارد.

عملیات های ماتریسی در پایتون

جمع ماتریس ها با یکدیگر

جمع یک ماتریس با عدد ثابت

که در آن تک تک خانه های ماتریس با عدد جمع خواهند شد.

ضرب ماتریس در یک عدد ثابت یا scale

که در آن تک تک خانه های ماتریس در عدد ضرب خواهند شد.

 

نرم اقلیدسی در ماتریس ها

که دارای ویژگی های زیر است

  • مقدار آن همواره بزرگتر مساوی صفر است.
  • اگر صفر شود تک تک درایه های ماتریس باید صفر شوند .
  • به ازای هر
  • به ازای هر 

 

برای یاد آوری ضرب ماتریس ها میتوانید اینجا را کلیک کنید.

معرفی چند ماتریس خاص

ماتریس همانی:  یک ماتریس مربعی است کهتمامی درایه های روی قطر اصلی یک و سایر آنها صفر هستند.

ماتریس قطری: یک ماتریس مربعی است که درایه های روی قطر اصلی عدد دارند و سایر آنها صفر هستند.

ماتریس ترا نهاده: ماتریسی است که جای سطر و ستون هایش باهم عوض شده باشند.

ماتریس انتقال: ماتریسی است که برای انتقال بردار ها از طریق ضرب استفاده میشود.

نکاتی درباره ی ضرب ماتریس ها:

  • ضرب ماتریس ها خاصیت جابه جایی ندارد AB!=BA.
  • تنها میتوان ماتریس های مربعی را به توان رساند.