چطور عکس های غیر هم اندازه و/یا با نسبت غیر ثابت را به یک شبکه عصبی بدهیم؟

شبکه های عصبی کانوولوشنی (CNN ها) نقطه ی تلاقی پردازش تصویر و هوش مصنوعی هستن. بعضی از نسخه های CNN ها، روی مجموعه داده های بزرگی مثل ImageNet به دقت های بالاتر از دقت سیستم بینایی انسان رسیدن جزو اولین حوزه هایی به حساب میان که کامپیوتر ها از انسان ها جلو افتادن.همونجوری که اطلاع دارید، شبکه های عصبی کانوولوشنی، لازم دارن که ورودی ای که بهشون میدیم، سایز یکسان و ثابتی داشته باشه. و این برای کسانی که میخوان توی یه کاربرد جدید از CNN ها استفاده کنن، یکم دردسر سازه. مثلا شما میاین از 10 تا منبع مختلف تصویر جمع می کنین، تا تعداد داده هایی که در اختیار دارین رو به حد قابل توجهی برسونین (و عمل training رو ممکن کنین) و مثلا تعداد داده هاتون به 5000 میرسه. اما وقتی شروع می کنین یه مدل هوش مصنوعی درست کنین، دقت می کنین و می بینین که هر کدوم از اون 10 تا منبع، عکس هایی با Resolution مختلف ارائه دادن و شبکه ی عصبی کانوولوشنی ای نمیتونه این عکسا رو دریافت کنه.امروز چند تا راهکار ساده برای سازگار کردن اندازه ی این تصاویر و آماده کردن دیتاست (DataSet) برای یه کار پردازش تصویری هیجان انگیز رو باهم مرور می کنیم.1- تغییر سایز به روش Stretch کردنفرض کنید یک تعداد تصویر با نسبت های مختلف و سایز های مختلف دارید. یک سایز استاندارد در نظر می گیرید (که بهتره یکی از پر تکرار ترین سایز های تصاویری که جمع آوری کردید باشه) مثلا اینجا در نظر می گیریم که این سایز 100*100 باشه. همه ی تصاویری که دارین رو به این سایز Stretch می کنین. مثلا یه تصویر که 120*120 هست، بدون تغییر نسبت طول به عرض و فقط با کمتر شدن Resolution به این سایز تبدیل میشه. و عکس هایی که نسبت متفاوتی دارن، با تغییر جزئی شکل به این سایز در میان. (که این یه مشکل جدی محسوب میشه)2- تغییر سایز به روش Zero Padding یا اضافه کردن قاب (*)فرض کنید بزرگترین سایز داخل مجموعه داده تون، 120*120 باشه. بعضی از عکس ها سایز 100*100 دارن و بعضی از اون ها سایز 120*50 و بعضی دیگه 70*120. توی این روش، هر تصویر رو در مرکز یه قاب 120*120 قرار میدیم، و بعدش هرجایی از قاب که خالی موند، رو با پیکسل های رنگ سیاه (یا هر رنگ دیگه ای که بر حسب کاربرد و تصاویر شما پس زمینه محسوب میشه) پر می کنیم. اینجوری، باعث میشیم تصویر 100*100، از هر طرف 10 پیکسل سیاه بهش اضافه بشه. همینطور تصویر 120*50 از بالا و پایین 35 پیکسل قاب سیاه بهش اضافه میشه. تصویر 70*120 هم از راست و چپ 25 پیکسل سیاه بهش اضافه میشه. (*: اینستاگرامی ها خوب میدونن این روش چجوری کار می کنه :دی)3- بریدن تصاویر به اندازه ی دلخواه (Crop کردن)این روش تقریبا برعکس روش قبلیه. اینجا یه سایز کوچیک (مثلا کوچیکترین سایز عکس داخل مجموعه داده) رو در نظر می گیریم و بقیه ی تصاویر رو وسط یه قاب به این اندازه میذاریم و اضافی هاشونو میبریم و میندازیم دور. همونطور که مشخصه، ممکنه اینجوری قسمت های مهمی از تصاویر رو دور انداخته باشیم پس موقع استفاده از این روش، خیلی دقت کنید. اگه میتونید، به صورت دستی، به جای این که مرکز تصاویر رو داخل قاب بذارید، مرکز توجه تصویر رو داخل قاب بذارید تا مطمئن بشین اطلاعات مهمی از تصویر رو حذف نمی کنید.4- ترکیب روش اول و روش دوم (Zero Padding + Stretching)این روش یه جورایی خوبی های دو روش اول رو باهم ترکیب می کنه. اینجوری که اولش میایم یه Ratio برای تصاویر در نظر میگیریم، مثلا 1:1 یعنی تصاویر مربعی. بعدش هر تصویر داخل مجموعه داده رو، با Zero Padding به این نسبت تبدیل می کنیم. یعنی اگه یه تصویر 100*90 داشته باشیم، 5 پیکسل از بالا و پایین بهش قاب سیاه اضافه می کنیم. بعد از این مرحله، همه ی تصاویر مربعی ای که داریم رو، به یه سایز مشخص مثلا 100*100 Stretch می کنیم. همونطوری که مشخصه، توی این روش، مشکل تغییر شکل ایجاد شده به خاطر Stretch کردن به نسبت های متفاوت، وجود نداره. البته هنوز یه مشکل وجود داره و اینه که رنگ سیاه اضافه شده ممکنه بر حسب کاربردی که مد نظر دارید، براتون مشکل ایجاد کنه و مثلا بخواید به جاش سبز یا قرمز استفاده کنید.5- تولید Patch های کوچیک از تصاویر، به صورت تصادفیاین روش یکی از روش هاییه که جدیدا بیشتر مورد استفاده قرار می گیره. توی این روش، به جای این که هر تصویر رو یک بار استفاده کنیم، از هر تصویر چندین Patch (تکه) با سایز ثابت برمیداریم و به مجموعه داده اضافه می کنیم. مثلا فرض کنید یه تصویر با اندازه ی 200*200 داریم. ولی اندازه ی Patch رو 100*100 در نظر گرفتیم. میایم یه تعداد نقطه ی شروع تصادفی داخل تصویر انتخاب می کنیم. مثلا نقاط (100, 100) (100, 25) (40, 90) (19, 0) و بعد میایم Patch های به اندازه ی 100*100 رو با شروع از این نقاط انتخاب می کنیم. برای این مثال، Patch هامون میشن:100, 100 ~ 200, 200100, 25 ~ 200, 12540, 90 ~ 140, 19019, 0 ~ 119, 100و حالا این Patch ها که هرکدوم اندازه اش 100*100 هست رو به مجموعه داده مون اضافه می کنیم. خب همونطور که اطلاع دارید، این روش علاوه بر این که مشکل سایز های مختلف تصاویر رو حل می کنه، یه تکنیک Data Augmentation هم محسوب میشه. (که خیلی به درد میخوره)6- هر روش ترکیبی دیگه ای که به ذهنتون میرسه...همونجوری که میدونین، هوش مصنوعی بدون خلاقیت، هیچ معنایی نداره. اگه یه نفر بیاد و بهتون بگه توی هوش مصنوعی برای حل فلان مشکل فقط و فقط یه راه وجود داره، میتونین با احتمال 99 درصد بهش بگین که "اشتباه می کنی!" برای این مشکل که امروز بررسی کردیم هم، فقط این چند تا راه حل وجود نداره و بر اساس کاربردی که مد نظر دارین و خلاقیتی که به خرج میدین، میتونین کار های خارق العاده ی دیگه ای انجام بدین.یه نکته هم که آخر کار میخوام اضافه کنم، توجه کردن به نوع ذخیره شدن تصاویر هست. مثلا اگه تصویری رو با استفاده از کتابخانه ی Opencv از روی حافظه میخونید، باید توجه کنید که این تصویر رو به فرمت BGR در میاره. در حالی که اگه همین کارو با استفاده از matplotlib انجام بدید، بهتون فرمت RGB میده. (یعنی محل کانال های رنگی این دو روش باهم فرق می کنه.) پس لطفا دقت کنید تا دیتای Consistent ای داشته باشید.همچنین حواستون باشه که هیچوقت دیتای اولیه رو دور نریزین. چون ممکنه بعدا متوجه بشین که توی یکی از مراحل Preprocessing، یه مشکل به وجود اومده و دیتا تون رو خدای ناکرده از دست بدین.امیدوارم نکاتی که امروز باهم بررسی کردیم به دردتون خورده باشه.اگه نظری در مورد این پست یا پیشنهادی در مورد پست های بعدی دارین، خوشحال میشم که بهم اطلاع بدینخوش باشین :)