قطعه بندی تصویر در پایتون — راهنمای کاربردی
در این مطلب، با مبحث «قطعه بندی تصویر» (Image Segmentation) و ابزارهای آن در «زبان برنامهنویسی پایتون» (Python Programming Language) آشنا خواهید شد. تکنیکهای قطعه بندی تصویر با نامهای دیگری نظیر بخش بندی تصویر (Image Segmentation) نیز شناخته میشوند. قطعه بندی تصویر (یا بخش بندی تصویر) یکی از زیر شاخههای مهم «پردازش تصویر» (Image processing) و «بینایی کامپیوتر» (Computer Vision) محسوب میشود که امروزه به یکی از فرایندهای استاندارد پردازش و دستکاری تصویر در بسیاری از نرمافزارها، کتابخانهها و ماژولهای برنامهنویسی تبدیل شده است.
در صورتی که شما از طرفداران مجموعه فیلمهای «نابودگر» (Terminator) باشید، بدون شک با این صحنه در قسمت دوم این مجموعه برخورد داشتهاید. در این فیلم، سازندگان «جلوه بصری» (Visual Effect) بسیار جالبی را به نمایش گذاشتند؛ جلوه بصری ویژه به نمایش گذاشته شده، به بینندگان اجازه میداد که خود را به جای یک روبات «سایبورگ» (Cyborg) به نام نابودگر (Terminator) تصور کنند و دنیا را از دید چنین موجودی ببینند.
در این جلوه ویژه بصری، که بعدها با عنوان «دید نابودگر» (Terminator Vision) معروف شد، با استفاده از فرایندی همانند قطعه بندی تصویر (Image Segmentation)، انسان موجود در فریم از «پس زمینه» (Background) جدا شده است. چنین جلوهای ممکن است که در سالهای انتهایی قرن بیستم، یک ویژگی بصری منحصر به فرد تلقی میشد، ولی امروزه قطعه بندی تصویر (یا بخش بندی تصویر) به یکی از قابلیتهای اصلی نرمافزارها، کتابخانهها و ماژولهای استاندارد پردازش تصویر (Image Processing) تبدیل شده است.
قطعه بندی تصویر
در بینایی کامپیوتر (Computer Vision)، قطعه بندی تصویر به فرایند تقسیمبندی یک «تصویر دیجیتال» (Digital Image) به چندین قطعه (Segment) یا ناحیه (Region) گفته میشود (مجموعهای از پیکسلها (Pixels) که به آنها «اشیاء تصویر» (Image Objects) نیز گفته میشود). هدف تکنیکهای بخش بندی تصویر، سادهسازی و یا تغییر نمایش اصلی یک تصویر به نمایشی (Representation) «با معنیتر» (More Meaningful) است که تجزیه و تحلیل تصویر را نیز آسانتر میکند.
از فرایند قطعه بندی تصویر معمولا جهت مشخص کردن موقعیت اشیاء (Locating Objects) و «مرزها» (Boundaries) در تصویر (خطوط و منحنیها (curves) از مرزهای قابل تشخیص در تصاویر دیجیتالی محسوب میشوند) استفاده میشود. به طور دقیقتر، به فرایند برچسبگذاری تمامی پیکسلهای موجود در یک تصویر دیجیتال، قطعه بندی تصویر (یا بخش بندی تصویر) گفته میشود؛ به طوری که پیکسلهایی که برچسب (Label) یکسان دارند، ویژگیهای مشخصه (Characteristics) خاصی را با یکدیگر به اشتراک میگذارند.
نتیجه فرایند قطعه بندی تصویر مجموعهای از قطعهها یا نواحی در تصویر خواهد بود که از کنار هم قرار دادن تمامی این نواحی، تصویر اصلی ایجاد خواهد شد. همچنین، نتیجه فرایند قطعه بندی تصویر میتواند مجموعهای از «کانتورهای» (Contours) استخراج شده از تصویر دیجیتال باشد. تمامی پیکسلهای موجود در یک ناحیه یا قطعه خاص در تصویر (حاصل از فرایند بخش بندی تصویر یا قطعه بندی تصویر)، بسته به برخی از مشخصهها یا ویژگیهای محاسبه شده از تصویر، نظیر «رنگ» (Color)، «شدت» (Intensity) یا «بافت» (Texture)، به یکدیگر شباهت دارند. در نقطه مقابل با توجه به همین مشخصهها یا ویژگیهای محاسبه شده از تصویر، نواحی یا قطعههای «همسایه» (Adjacent | مجاور) به طرز قابل توجهی متفاوت از این قطعه یا ناحیه خاص خواهند بود.
در صورتی که از روشهای قطعه بندی تصویر جهت پردازش مجموعهای از تصاویر دیجیتالی استفاده شود (معمولا در حوزه تصویربرداری پزشکی یا Medical Imaging)، میتوان از کانتورهای حاصل از قطعه بندی تصویر و البته با بهکارگیری الگوریتمهای «درونیابی» (Interpolation) نظیر «مکعبهای متحرک» (Marching Cubes)، جهت پیادهسازی کاربردهای «بازسازی سهبُعدی» (3D Reconstruction) استفاده کرد.
کاربردهای قطعه بندی تصویر
از جمله کاربردهای عملی قطعه بندی (یا بخش بندی تصویر) تصویر میتوان به موارد زیر اشاره کرد:
- کاربردهای «بازیابی تصویر مبتنی بر محتوا» (Content-based Image Retrieval)
- «بینایی ماشین» (Machine Vision)
- تصویربرداری پزشکی (Medical Imaging) از جمله تولید تصاویر سهبُعدی رندر شده (Rendered) با استفاده از تصاویر حاصل از مغز نگاری کامپیوتری (Computed Tomography Scanning | CT-Scan) و یا تصاویر حاصل از «تصویربرداری رزونانس مغناطیسی» (Magnetic Resonance Imaging | MRI).
- شناسایی موقعیت تومورها (Tumors) و دیگر پاتولوژیها (Pathologies) در بدن
- سنجش حجم بافتهای زنده (Tissues) در بدن
- کاربردهای تشخیص پزشکی و مطالعه ساختارهای آناتومی بدن
- برنامهریزی عملهای جراحی
- شبیهسازی جراحی مجازی
- ناوبری در حین عمل جراحی؛ به عنوان بخشی از سیستمهای جراحی به کمک کامپیوتر (Computer-assisted Surgery)
- تشخیص اشیاء (Object Detection)
- تشخیص عابر پیاده (Pedestrian Detection)
- تشخیص چهره (Face Detection)
- تشخیص چراغ ترمز (Brake Light Detection)
- موقعیتیابی کردن اشیاء در تصاویر ماهوارهای (Satellite Images) نظیر راهها، جنگلها، مزارع و سایر موارد.
- کاربردهای مرتبط با بازشناسی (Recognition)
- «بازشناسی چهره» (Face Recognition)
- «بازشناسی اثر انگشت» (Fingerprint Recognition)
- «بازشناسی عنبیه» (Iris Recognition)
- سیستمهای کنترل ترافیک
- نظارت ویدئویی
علاوه بر کاربردهای ذکر شده، تاکنون الگوریتمهای همه منظوره مختلفی جهت پیادهسازی کاربردهای قطعه بندی تصویر توسعه داده شده است. برای اینکه چنین کاربردهایی مفید باشند باید با «دانش مختص دامنه» (Domain Specific Knowledge) ترکیب شوند تا بتوانند به شکل مؤثری جهت حل کردن مسائل بخش بندی تصویر در دامنههای خاص مورد استفاده قرار بگیرند.
قطعه بندی تصویر در پایتون
به احتمال بسیار زیاد، بسیاری از خوانندگان و مخاطبان این مطلب با نرمافزارهای پردازش تصویر نظیر فتوشاپ آشنایی دارند. بسیاری از این نرمافزارها، امکانات پردازشی جالبی، جهت ویرایش و دستکاری تصاویر دیجیتال، در اختیار کاربران قرار میدهند. به عنوان نمونه، یکی از امکانات جالبی که این دسته از نرمافزارها در اختیار کاربران قرار میدهند، امکان حذف پس زمینه (Background) از عکسهای خانوادگی و قرار دادن یک پس زمینه جدید در این عکسها است. چنین فرایندی نیازمند این است که نرمافزارهای پردازش و ویرایش تصویر قادر به شناسایی اشیاء موجود در تصویر (افراد، اشیاء مورد علاقه در تصویر و سایر موارد) باشند.
در چنین حالتی، از الگوریتمهای قطعه بندی تصویر جهت شناسایی اشیاء و یا افراد موجود در تصاویر استفاده میشود. تاکنون، ابزارها و کتابخانههای برنامهنویسی (Libraries) زیادی با هدف توسعه سیستمهای بخش بندی تصویر (قطعه بندی تصویر) پیادهسازی شدهاند. در این مطلب، نحوه قطعه بندی تصویر با استفاده از کتابخانه scikit-image در زبان برنامهنویسی پایتون مورد بررسی قرار گرفته خواهد شد؛ کتابخانه scikit-image، یکی از کتابخانههای توسعه داده شده جهت انجام عملیات پردازش تصویر در پایتون محسوب میشود.
کتابخانه scikit-image در پایتون
کتابخانه scikit-image، کتابخانه اختصاصی برای مقاصد پردازش تصویر در زبان پایتون محسوب میشود. این ابزار کاربردی، مجموعهای از الگوریتمهای شناخته شده جهت پردازش و دستکاری (Manipulation) تصاویر دیجیتالی را در اختیار کاربران و برنامهنویسان قرار میدهد. کدهایی که توسط توسعهدهندگان این کتابخانه در اختیار جامعه برنامهنویسی قرار گرفته شدهاند، از کیفیت بالایی برخوردار هستند و توسط جامعه برنامهنویسی بسیار فعال و متشکل از توسعهدهندگان داوطلب کد نویسی شدهاند. استفاده از کدهای این کتابخانه برای توسعه برنامههای کاربردی مرتبط با حوزه پردازش تصویر و توزیع آنها در سطح وب، برای عموم آزاد است و هیچگونه محدودیتی در این زمینه وجود ندارد.
نصب کتابخانه scikit-image در پایتون
برای نصب کتابخانه scikit-image در سیستمهای عامل مختلف، میتوان از دستورات زیر استفاده کرد:
1pip install -U scikit-image(Linux and OSX)
2pip install scikit-image(Windows)
3# For Conda-based distributions
4conda install scikit-image
پیش از اینکه روشهای قطعه بندی تصویر در پایتون و کتابخانه scikit-image مورد بررسی قرار بگیرند، لازم است تا آشنایی ابتدایی با اکوسیستم کتابخانه scikit-image حاصل شود و نحوه پردازش تصویر (بارگذاری تصاویر سیاه و سفید، بارگذاری تصاویر رنگی، بارگذاری همزمان چندین تصویر و ذخیره کردن تصاویر) توسط آن مورد بررسی قرار بگیرد.
بارگذاری تصاویر سیاه و سفید (Black and White) و سطح خاکستری (Grey-Level) از کتابخانه scikit-image
«ماژول داده» (Data Module) کتابخانه scikit-image شامل مجموعهای از تصاویر نمونه است که معمولا در فرمتهای PNG و JPG ذخیره شدهاند.
1from skimage import data
2import numpy as np
3import matplotlib.pyplot as plt
4image = data.binary_blobs()
5plt.imshow(image, cmap='gray')
بارگذاری تصاویر رنگی (Colored Images) از کتابخانه scikit-image
علاوه بر تصاویر سطح خاکستری، مجموعهای از تصاویر رنگی نیز در کتابخانه scikit-image تعبیه شدهاند:
1from skimage import data
2import numpy as np
3import matplotlib.pyplot as plt
4image = data.astronaut()
5plt.imshow(image)
بارگذاری تصاویر از یک منبع خارجی (External Source)
جهت بارگذاری تصاویر از یک منبع خارجی، از ماژول I/O (ورودی-خروجی) کتابخانه scikit-image استفاده میشود:
1# The I/O module is used for importing the image
2from skimage import data
3import numpy as np
4import matplotlib.pyplot as plt
5from skimage import io
6image = io.imread('skimage_logo.png')
7plt.imshow(image);
بارگذاری چندین تصویر به طور همزمان در کتابخانه scikit-image
کتابخانه scikit-image این امکان را برای برنامهنویسان و توسعهدهندگان برنامههای کاربردی مرتبط با حوزه پردازش تصویر فراهم آورده است تا بتوانند چندین تصویر را به طور همزمان در سیستم بارگذاری کنند. برای چنین کاری، میتوان از قطعه کدی مشابه کدهای زیر استفاده کرد:
1images = io.ImageCollection('../images/*.png:../images/*.jpg')
2print('Type:', type(images))
Type: <class 'skimage.io.collection.ImageCollection'>
ذخیره کردن تصاویر در کتابخانه scikit-image
جهت ذخیره کردن تصاویر توسط کتابخانه scikit-image میتوان از قطعه کد زیر استفاده کرد:
1#Saving file as 'logo.png'
2io.imsave('logo.png',image)
الگوریتمهای قطعه بندی تصویر (بخش بندی تصویر)
در بخش قبلی، آشنایی ابتدایی با سازوکارهای ابتدایی تعبیه شده در کتابخانه scikit-image جهت پردازش تصویر حاصل شد. در مرحله بعد، شایعترین و پرکاربردترین الگوریتمهای قطعه بندی تصویر معرفی خواهند شد. همچنین، پیادهسازی این الگوریتمها توسط کتابخانه scikit-image مورد بررسی قرار گرفته خواهند شد.
همانطور که پیش از این نیز اشاره شد، به فرایند تقسیمبندی یک تصویر دیجیتال به چندین قطعه (Segment) یا ناحیه (Region)، قطعه بندی تصویر گفته میشود. هدف تکنیکهای بخش بندی تصویر (Image Segmentation)، سادهسازی و یا تغییر نمایش اصلی یک تصویر به نمایشی است که تجزیه و تحلیل تصویر را آسانتر میکند و از همه مهمتر، اطلاعات به مراتب با معنیتری را در اختیار سیستم پردازش تصویر یا بینایی کامپیوتر قرار میدهد.
در این مطلب، برای بخش بندی تصویر از یک رویکرد ترکیبی متشکل از الگوریتمهای «قطعهبندی نظارت شده» (Supervised Segmentation) و «قطعهبندی نظارت نشده» (Unsupervised Segmentation) استفاده میشود. در ادامه، برخی از الگوریتمهای قطعه بندی تصویر (یا بخش بندی تصویر) که در کتابخانه scikit-image پیادهسازی شدهاند، معرفی میشوند:
- الگوریتمهای قطعه بندی تصویر (Image Segmentation)
- الگوریتمهای نظارت شده (Supervised Algorithms)
- قطعه بندی تصویر به روش «آستانهگذاری» (Thresholding) با بهرهگیری از «دانش پیشین» (Prior Knowledge) یا «درونداد انسانی» (Human Input)
- قطعه بندی تصویر به روش «قدم زدن تصادفی» (Random Walk)
- قطعه بندی تصویر به روش «کانتور فعال» (Active Contour)
- الگوریتمهای نظارت نشده (Unsupervised Algorithms)
- قطعه بندی تصویر به روش «آستانهگذاری» (Thresholding) بدون بهرهگیری از «دانش پیشین» (Prior Knowledge) یا «درونداد انسانی» (Human Input)
- قطعه بندی تصویر به روش «قطعه بندی ساده، خطی و تکراری» (Simple Linear Iterative Clustering | SLIC)
- قطعه بندی تصویر به روش Felzenszwalb
- الگوریتمهای نظارت شده (Supervised Algorithms)
الگوریتمهای نظارت شده (Supervised) جهت قطعه بندی تصویر
در الگوریتمهای نظارت شده، جهت بخش بندی (قطعه بندی) صحیح تصاویر به نواحی دربرگیرنده اشیاء، نیاز به دانش پیشین (در قالب درونداد (Input) انسانی) جهت راهنمایی الگوریتم وجود دارد.
الگوریتمهای نظارت نشده (Unsupervised) جهت قطعه بندی تصویر
در این دسته از الگوریتمهای قطعه بندی تصویر (Image Segmentation)، جهت تضمین عملکرد بهینه سیستم، نیازی به دانش پیشین وجود ندارد. روش های بخش بندی تصویر به شیوه نظارت نشده سعی میکنند به طور خودکار، تصاویر را به مجموعهای از نواحی بامعنی (Meaningful Regions) تقسیمبندی کنند. با این حال، بسته به نوع الگوریتم استفاده شده، ممکن است این امکان در اختیار کاربران قرار داده شود تا جهت دستیابی به نتایج مطلوب، تنظیمات خاصی از الگوریتم را تغییر دهند.
در ابتدا، سادهترین روش قطعه بندی تصویر (بخش بندی تصویر) به نام روش آستانهگذاری (Thresholding) مورد بررسی قرار خواهد گرفت.
روش آستانهگذاری (Thresholding) جهت قطعه بندی تصویر
یکی از ساده روشهای جدا کردن اشیاء از یک پس زمینه (قطعه بندی تصویر به پس زمینه و اشیاء موجود در آن)، انتخاب پیکسلهایی است که «مقادیر شدت» (Intensity Values) آنها بیشتر یا کمتر از یک «حد آستانه» (Threshold) باشد. استفاده از چنین تکنیکی، جهت بخش بندی تصویر به پس زمینه و اشیاء موجود در آن (جدا کردن اشیاء از پس زمینه)، میتواند بسیار مفید واقع شود.
برای نمایش نحوه عملکرد روش آستانهگذاری در (Thresholding) بخش بندی تصویر دیجیتال، از تصویری به نام page که در کتابخانه scikit-image تعبیه شده است استفاده میشود.
ابتدا توابع و کتابخانههای لازم جهت پیادهسازی سیستم قطعه بندی تصویر به روش آستانهگذاری import میشوند:
1import numpy as np
2import matplotlib.pyplot as plt
3import skimage.data as data
4import skimage.segmentation as seg
5import skimage.filters as filters
6import skimage.draw as draw
7import skimage.color as color
سپس، با استفاده از قطعه کد زیر یک تابع ساده جهت نمایش تصاویر کد نویسی میشود:
1def image_show(image, nrows=1, ncols=1, cmap='gray'):
2 fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(14, 14))
3 ax.imshow(image, cmap='gray')
4 ax.axis('off')
5 return fig, ax
با استفاده از دستورات زیر، تصویر page نمایش داده میشود:
1text = data.page()
2image_show(text)
همانطور که در تصویر بالا قابل مشاهده است، تصویر بارگذاری شده کمی تاریک است. با این حال، این امکان وجود دارد که مقدار (منظور، مقدار شدت) مناسبی را به عنوان حد آستانه (Threshold) انتخاب کرد و از این طریق، به بخش بندی معقولی از تصویر بارگذاری شده دست یافت؛ بدون اینکه نیاز به استفاده از روشهای بخش بندی تصویر (Segmentation) پیشرفتهتر وجود داشته باشد. برای انتخاب مقدار شدت مناسب به عنوان حد آستانه، از مفهوم «هیستوگرام» (Histogram) استفاده میشود.
هیستوگرام یک گراف است که تعداد پیکسلهای موجود در یک تصویر، در مقادیر متفاوتی از شدت (Intensity Values) را نشان میدهد. به بیان سادهتر، هیستوگرام گرافی است که در آن محور افقی، تمامی مقادیر شدت پیکسلهای موجود در تصویر را نمایش میدهد، در حالی که محور عمودی تناوب (Frequency) این مقادیر را نشان میدهد.
1fig, ax = plt.subplots(1, 1)
2ax.hist(text.ravel(), bins=32, range=[0, 256])
3ax.set_xlim(0, 256);
در این مثال، هیستوگرام متناظر با یک تصویر 8 بیتی را نشان میدهد، در نتیجه، در مجموع 256 مقدار ممکن در محور افقی، جهت نمایش مقادیر شدت پیکسلهای موجود در تصویر، وجود خواهد داشت. همانطور که در تصویر بالا نیز قابل مشاهده است، تعداد زیادی از پیکسلهای موجود در تصویر تقریبا روشن هستند (پیکسلهای با مقدار شدت برابر با 0 (صفر)، نمایش دهنده رنگ سیاه در تصویر هستند و مقادیر شدت برابر با 255، پیکسلهای سفید موجود در تصویر را نمایش میدهند).
پیکسلهای روشن موجود در تصویر، به احتمال زیاد پشت زمینه سفید تصویر را نمایندگی میکنند. در یک روش ایدهآل قطعهبندی مبتنی بر هیستوگرام، مقادیر شدت پیکسلهای موجود در تصویر «دو مُدی» (Bi-Modal) هستند؛ به عبارت دیگر، مقادیر شدت پیکسلهای موجود در یک تصویر، اطراف دو مقدار شدت متفاوت تمرکز خواهند داشت. چنین حالتی این امکان را برای کاربران فراهم میکند تا بتوانند با انتخاب یک مقدار میانه (مقدار میانه مقداری است که درست وسط دو مقدار شدتی قرا میگیرد که غالب پیکسلهای تصویر در اطراف آنها تمرکز دارند) به عنوان حد آستانه، نواحی یا قطعههای موجود در تصویر را به راحتی جداسازی کنند.
در روشهای قطعهبندی مبتنی بر هیستوگرام، در صورتی که دو ناحیه موجود در تصویر، شدت رنگ متفاوتی از یکدیگر نشان دهند، سیستم به راحتی میتواند این نواحی را از یکدیگر جدا کند. در ادامه و از طریق روش آستانهگذاری، نحوه قطعه بندی تصویر (بخش بندی تصویر) ورودی به سیستم نمایش داده خواهد شد.
آستانهگذاری نظارت شده (Supervised Thresholding)
از آنجایی که قرار است مقدار حد آستانه (Threshold) توسط کاربر انتخاب شود، به این روش بخش بندی تصویر (Image Segmentation)، آستانهگذاری نظارت شده گفته میشود.
در ابتدا، مقدار شدت برابر با 50، به عنوان مقدار حد آستانه انتخاب میشود:
1text_segmented = text>50
2
3
4image_show(text_segmented);
سپس، از مقدار حد آستانه برابر با 70 جهت جداسازی پس زمینه استفاده میشود:
1text_segmented = text>70
2
3
4image_show(text_segmented);
در نهایت، مقدار شدت برابر با 120، به عنوان حد آستانه انتخاب میشود. تصویر زیر خروجی حاصل از قطعه بندی تصویر (بخش بندی تصویر) به روش آستانهگذاری نظارت شده را نشان میدهد.
همانطور که در تصویر بالا قابل مشاهده است، با توجه به سایه (Shadow) ایجاد شده در تصویر بالا، قطعهبندی خوبی از تصویر ورودی به سیستم ایجاد نشده است. بنابراین، استفاده از روش آستانهگذاری نظارت شده جهت قطعه بندی تصویر نتایج خوبی رقم نخواهد زد. در ادامه، از روش آستانهگذاری نظارت نشده (Unsupervised Thresholding) جهت بخش بندی تصویر (قطعه بندی تصویر) استفاده میشود.
آستانهگذاری نظارت نشده (Unsupervised Thresholding)
در کتابخانه Scikit-image مجموعهای ار روشهای آستانهگذاری خودکار جهت قطعه بندی تصویر پیادهسازی شدهاند. این دسته از روشهای قطعه بندی تصویر (Image Segmentation) نیازی به درونداد انسانی (Human Input) جهت انتخاب مقدار بهینه حد آستانه ندارند. برخی از روشهای قطعه بندی تصویر (بخش بندی تصویر) با استفاده از آستانهگذاری نظارت نشده عبارتند از:
- روش otsu
- روش li
- روش local
قطعه بندی تصویر (بخش بندی تصویر) با استفاده از روش otsu
1text_threshold = filters.threshold_otsu(text) # Hit tab with the cursor after the underscore, try several methods
2
3image_show(text > text_threshold);
قطعه بندی تصویر (بخش بندی تصویر) با استفاده از روش li
1text_threshold = filters.threshold_li(text) # Hit tab with the cursor after the underscore, try several methods
2
3image_show(text > text_threshold);
قطعه بندی تصویر (بخش بندی تصویر) با استفاده از روش Local
1text_threshold = filters.threshold_local(text,block_size=51, offset=10)
2image_show(text > text_threshold);
همانطور که در تصاویر بالا قابل مشاهده است، روش Local نتایج به مراتب بهتری نسبت به دیگر روشهای آستانهگذاری نظارت نشده در قطعه بندی تصویر از خود نشان میدهد. همچنین، نواحی نویزی (سایه ایجاد شده هنگام بخش بندی تصویر) تا حد زیادی از بین رفتهاند.
قطعه بندی تصویر توسط روشهای نظارت شده (Supervised Segmentation)
همانطور که در بخشهای پیشین مشاهده شد، روشهای آستانه گذاری سادهترین روشهای موجود جهت قطعه بندی تصویر محسوب میشوند. همچنین روشهای آستانهگذاری، در قطعه بندی تصویر با کنتراست بالا (High Contrast Image) با مشکل مواجه میشوند؛ جهت بخش بندی تصویری که از کنتراست بالایی برخوردار هستند، باید از روشهای قطعهبندی پیشرفتهتری استفاده شود.
جهت قطعه بندی تصویر با استفاده از روشهای نظارت شده، از یک تصویر موجود در وب استفاده شده است. در این بخش هدف این است که با استفاده از روشهای قطعهبندی نظارت شده، قسمت سَر (Head Portion) شخص موجود در تصویر از دیگر قسمتهای تصویر جداسازی شود؛ برای انجام چنین کاری، استفاده از روشهای آستانهگذاری مناسب نیست و ضروری است تا از روشهای پیشرفته بخش بندی تصویر استفاده شود. ابتدا با استفاده از قطعه کد زیر، تصویر مورد نظر در سیستم بخش بندی تصویر (قطعه بندی تصویر) بارگذاری میشود:
1# import the image
2from skimage import io
3image = io.imread('girl.jpg')
4plt.imshow(image);
معمولا توصیه میشود که پیش از انجام هرگونه فرایند پردازشی (از جمله قطعه بندی تصویر) روی تصاویر دیجیتالی، از روشهای فیلتر کردن (Filtering) تصاویر (با هدف حذف نویز (Noise Removal | De-Noising)) استفاده شود. یا این حال، از آنجایی که تصویر ورودی حاوی نویز بسیار کمی است، بدون اعمال روشهای فیلتر کردن و حذف نویز، از این تصویر جهت پیادهسازی سیستم بخش بندی تصویر استفاده میشود. در مرحله بعد، با استفاده از تابع rgb2gray، تصویر رنگی ورودی به تصویر سطح خاکستری (Grey-Level) تبدیل میشود.
1image_gray = color.rgb2gray(image)
2image_show(image_gray);
در این بخش و جهت قطعه بندی تصویر (بخش بندی تصویر) ورودی با استفاده از روشهای نظارت شده، از دو تکنیک کاملا متفاوت از یکدیگر استفاده میشود؛ قطعه بندی تصویر به روش «قدم زدن تصادفی» (Random Walk) و قطعه بندی تصویر به روش «کانتور فعال» (Active Contour).
قطعه بندی تصویر به روش کانتور فعال
به تکنیکهای مبتنی بر قطعه بندی تصویر به روش کانتور فعال، روشهای Snakes نیز گفته میشود. در روشهای کانتور فعال، ابتدا یک کانتور یا خط تعریف شده توسط کاربر، اطراف ناحیه مورد نظر «مقداردهی اولیه» (Initialization) میشود. سپس، کانتور یا خط تعریف شده به آهستگی منقبض میشود؛ در چنین حالتی، کانتور یا جذب مناطق روشن و لبهها (Edges) میشود و یا از مناطق روشن و لبههای موجود در تصویر فاصله میگیرد.
برای بخش بندی تصویر ورودی با استفاده از روش کانتور فعال، ابتدا با استفاده از قطعه کد زیر یک دایره (Circle) اطراف سَر شخص کشیده میشود تا کانتور (یا همان Snake) مقداردهی اولیه شود.
1def circle_points(resolution, center, radius):
2 """
3 Generate points which define a circle on an image.Centre refers to the centre of the circle
4 """
5 radians = np.linspace(0, 2*np.pi, resolution)
6 c = center[1] + radius*np.cos(radians)#polar co-ordinates
7 r = center[0] + radius*np.sin(radians)
8
9 return np.array([c, r]).T
10# Exclude last point because a closed path should not have duplicate points
11points = circle_points(200, [80, 250], 80)[:-1]
با استفاده از تابع بالا، مختصات X و Y نقطههای موجود روی حاشیه دایره محاسبه میشود. از آنجایی که پارامتر resolution با عدد 200 مقداردهی اولیه شده است، تعداد 200 نقطه روی حاشیه دایره تولید میشود.
1fig, ax = image_show(image)
2ax.plot(points[:, 0], points[:, 1], '--r', lw=3)
در مرحله بعد، الگوریتم از طریق «برازش» (Fitting) یک منحنی بسته (Closed Curve) روی لبههای چهره، چهره (سَر) شخص را از تصویر جداسازی میکند؛ از این طریق، روش کانتور فعال، فرایند قطعه بندی تصویر ورودی را انجام میدهد.
1snake = seg.active_contour(image_gray, points)
2fig, ax = image_show(image)
3ax.plot(points[:, 0], points[:, 1], '--r', lw=3)
4ax.plot(snake[:, 0], snake[:, 1], '-b', lw=3);
برای دستیابی به نتایج قطعهبندی بهتر میتوان پارامترهای alpha و beta الگوریتم کانتور فعال را تغییر داد. انتخاب مقادیر بالاتر برای پارامتر alpha سبب میشود تا الگوریتم قطعه بندی تصویر با سرعت بیشتری اطراف لبهها منقبض (Contract) شود. همچنین، انتخاب مقادیر بالاتر برای پارامتر beta سبب هموارتر شدن کانتور یا Snake ایجاد شده اطراف لبهها (Edges) میشود.
1snake = seg.active_contour(image_gray, points,alpha=0.06,beta=0.3)
2fig, ax = image_show(image)
3ax.plot(points[:, 0], points[:, 1], '--r', lw=3)
4ax.plot(snake[:, 0], snake[:, 1], '-b', lw=3);
قطعه بندی تصویر به روش «قدم زدن تصادفی» (Random Walk)
در این روش قطعه بندی تصویر (Image Segmentation)، کاربر به صورت تعاملی یک مجموعه کوچک از پیکسلهای موجود در تصویر را برچسبگذاری میکند؛ به این پیکسلها، «برچسب» (Label) نیز گفته میشود. در روش قدم زدن تصادفی و با در اختیار داشتن مجموعهای از پیکسلهای برچسبگذاری شده (Label)، کاربر قادر خواهد بود از طریق روشهای آماری، احتمال اینکه یک Walker تصادفی (که در هر مرحله، حرکت خود را از هر کدام از پیکسلهای موجود در تصویر (به طور تصادفی) آغاز میکند) به یکی از پیکسلهای برچسبگذاری شده زودتر همگرا شود را محاسبه کند.
با اختصاص دادن هر کدام از پیکسلهای موجود در تصویر ورودی به برچسبی (Label) که بیشترین احتمال برای آن محاسبه شده است (به عبارت دیگر، پیکسل به برچسبی اختصاص داده میشود که با بیشترین احتمال و زودتر به آن همگرا خواهد شد)، الگوریتم قدم زدن تصادفی (Random Walk) قادر خواهد بود به شکل بهینهای تصویر ورودی را قطعه بندی کند؛ به عبارت دیگر، الگوریتم قطعه بندی تصویر نواحی مختلف موجود در تصویر را با کیفیت بالایی مشخص خواهد کرد.
همانند روش قبلی، از دایره برای مشخص کردن نواحی دربرگیرنده صورت (سَر) شخص و مشخص کردن پیکسلهای مجموعه Label استفاده میشود؛ شایان ذکر است که میتوان از روشهای دیگر نیز برای مقداردهی اولیه نواحی دربرگیرنده سَر شخص و مشخص کردن پیکسلهای مجموعه Label استفاده کرد ولی برای سادگی کار، از شکل دایره مرحله قبل استفاده میشود.
یکی از ورودیهای مورد انتظار الگوریتم قدم زدن تصادفی، تصویر نمایش دهنده پیکسلهای مجموعه Label است. برای چنین کاری از یک تصویر متشکل از دو دایره استفاده میشود؛ دایره بزرگتر تمام چهره شخص را در بر خواهد گرفت و دایره کوچکتر، روی محدوده وسط چهره شخص قرار میگیرد.
1indices = draw.circle_perimeter(80, 250,20)#from here
2image_labels[indices] = 1
3image_labels[points[:, 1].astype(np.int), points[:, 0].astype(np.int)] = 2
4image_show(image_labels);
در مرحله بعد، الگوریتم قدم زدن تصادفی (Random Walk) جهت بخش بندی تصویر اجرا میشود:
1image_segmented = seg.random_walker(image_gray, image_labels)
2# Check our results
3fig, ax = image_show(image_gray)
4ax.imshow(image_segmented == 1, alpha=0.3);
همانطور که در تصویر بالا مشخص است، الگوریتم به خوبی نتوانسته است «لبههای» (Edges) چهره شخص را شناسایی کند. جهت برطرف کردن این مشکل، میتوان پارامتر beta را تنظیم کرد. به عبارت دیگر، الگوریتم بخش بندی تصویر با مقادیر مختلف پارامتر beta اجرا و مقدار پارامتری که به بهترین شکل ممکن قادر به قطعه بندی تصویر است، به عنوان مقدار مناسب پارامتر beta انتخاب میشود. پس از چندین بار اجرای الگوریتم قطعه بندی تصویر با مقادیر مختلف پارامتر beta، مقدار 3000 به عنوان مقدار بهینه این پارامتر انتخاب شد.
1image_segmented = seg.random_walker(image_gray, image_labels, beta = 3000)
2# Check our results
3fig, ax = image_show(image_gray)
4ax.imshow(image_segmented == 1, alpha=0.3);
همانطور که در تصویر بالا قابل مشاهده است، الگوریتم قطعه بندی تصویر با استفاده از روش قدم زدن تصادفی (Random Walk) قادر است به شکل مناسبی چهره شخص را از تصویر جدا کند. در غالب روشهای نظارت شده قطعه بندی تصویر (Image Segmentation)، نیاز است تا ورودیهای خاص الگوریتم توسط کاربر مشخص و مقادیر بهینه برخی از پارامترها (معمولا به صورت دستی) نیز انتخاب شوند. با این حال، خبره کاربر انسانی همیشه در اختیار سیستم نخواهد بود تا بتواند مقادیر ورودیهای خاص الگوریتمهای قطعه بندی تصویر و یا مقادیر بهینه پارامترها را مشخص کند. خوشبختانه، در چنین حالتی از دسته خاصی از الگوریتمهای قطعه بندی تصویر به نام الگوریتمهای «قطعهبندی نظارت نشده» (Unsupervised Segmentation) استفاده میشود.
قطعه بندی تصویر توسط روشهای نظارت نشده (Unsupervised Segmentation)
در الگوریتمهای قطعه بندی تصویر توسط روشهای نظارت نشده، نیازی به در اختیار داشتن دانش پیشین (Prior Knowledge) وجود ندارد. یک تصویر دیجیتال را در نظر بگیرید؛ این تصویر به قدری بزرگ است که در نظر گرفتن تمام پیکسلهای آن (هنگام بخش بندی تصویر) به طور همزمان عملا غیر ممکن است. در چنین حالتی، الگوریتمهای قطعه بندی تصویر توسط روشهای نظارت نشده، یک تصویر را به مجموعهای «زیر ناحیهها» (Subregion) تقسیم بندی میکند؛ بنابراین، به جای پردازش میلیونها پیکسل به طور همزمان، الگوریتم قطعه بندی تصویر تنها پیکسلهای موجود در هر کدام از زیر ناحیهها را به طور همزمان پردازش میکند. دو الگوریتم قطعهبندی که در این مطلب مورد بررسی قرار میگیرند، عبارتند از:
- قطعه بندی تصویر به روش «قطعه بندی ساده، خطی و تکراری» (Simple Linear Iterative Clustering | SLIC)
- قطعه بندی تصویر به روش Felzenszwalb
قطعه بندی تصویر به روش «قطعه بندی ساده، خطی و تکراری» (Simple Linear Iterative Clustering | SLIC)
الگوریتم قطعهبندی SLIC از یک الگوریتم «یادگیری ماشین» (Machine Learning) به نام K-Means جهت قطعه بندی تصویر استفاده میکند؛ الگوریتم K-Means، یکی از روشهای معروف «خوشهبندی» (Clustering) دادهها محسوب میشود. در این روش بخش بندی تصویر (Image Segmentation)، مقادیر شدت پیکسلهای تصویر به عنوان ورودی دریافت میشود و الگوریتم سعی میکند تا تصویر ورودی را به مجموعهای از زیر ناحیهها تقسیمبندی کند (تعداد زیر ناحیهها باید از پیش مشخص باشد).
الگوریتم قطعهبندی SLIC با تصاویر رنگی کار میکند. بنابراین از تصویر اصلی استفاده خواهد شد:
1image_slic = seg.slic(image,n_segments=155)
روش کار الگوریتم قطعهبندی SLIC بدین صورت است که ابتدا مقادیر شدت پیکسلهای هر کدام از زیر ناحیههای (Sub-Regions) موجود در تصویر اصلی، به میانگین مقدار شدت پیکسلهای ناحیه نگاشت میشوند. در مرحله بعد، تصویر به مجموعهای از نواحی تجزیه میشود که پیکسلهای موجود در هر کدام از این نواحی، تا حدی شبیه به یکدیگر هستند.
1# label2rgb replaces each discrete label with the average interior color
2image_show(color.label2rgb(image_slic, image, kind='avg'));
بنابراین همانطور که در تصویر بالا نیز مشخص است، تصویر رنگی ورودی، با استفاده از الگوریتم بخش بندی تصویر (Image Segmentation)، به مجموعهای متشکل از 155 ناحیه تقسیمبندی شده است.
قطعه بندی تصویر به روش Felzenszwalb
در قطعه بندی تصویر به روش Felzenszwalb، از یک الگوریتم یادگیری ماشین به نام «خوشهبندی به روش درخت پوشای کمینه» (Minimum-spanning Tree Clustering) استفاده میشود؛ روش خوشهبندی به روش درخت پوشای کمینه، یک الگوریتم برای خوشهبندی پویای دادهها محسوب میشود. روش Felzenszwalb تعداد خوشههایی که تصویر ورودی بر اساس آن، به نواحی تشکیل دهنده تقسیمبندی میشود را مشخص نمیکند. این روش قطعه بندی تصویر (Image Segmentation)، یک تصویر ورودی را به هر تعداد زیر ناحیه که مناسب بداند، تقسیمبندی میکند.
1image_felzenszwalb = seg.felzenszwalb(image)
2image_show(image_felzenszwalb);
همانطور که در تصویر بالا مشخص است، تعداد خوشههای (زیر ناحیه) موجود در تصویر بسیار زیاد است. برای مشخص کردن تعداد زیر ناحیههای منحصر به فرد موجود در تصویر، از دستور زیر استفاده میشود:
1np.unique(image_felzenszwalb).size
2440
در مرحله بعد، همانند الگوریتم SLIC، مقادیر شدت پیکسلهای هر کدام از زیر ناحیههای تصویر اصلی، به میانگین مقدار شدت پیکسلهای ناحیه نگاشت میشوند:
1image_felzenszwalb_colored = color.label2rgb(image_felzenszwalb, image, kind='avg')
2image_show(image_felzenszwalb_colored);
همانطور که در تصویر بالا مشاهده میشود، تعداد زیر ناحیههای موجود در تصویر معقولتر شده است (نسبت به تصویر قبلی به مراتب کمتر شده است). در صورتی که کاربر تعداد زیر ناحیه کمتری را برای تصویر ورودی در نظر داشته باشد، میتواند مقدار پارامتر Scale را تغییر دهد و یا زیر ناحیههایی را که شباهت زیادی با یکدیگر دارند، ترکیب کند. به چین رویکردی Over-Segmentation گفته میشود.
تصاویری که در نتیجه قطعه بندی تصویر با استفاده از روش Felzenszwalb حاصل میشود، بیشتر شبیه به تصاویر پوستری (Posterized) هستند؛ به عبارت دیگر، چنین تصاویری در نتیجه کاهش تعداد رنگهای موجود در تصویر اصلی حاصل میشود. برای کم کردن تعداد زیر ناحیههای موجود در تصویر از طریق ترکیب کردن زیر ناحیههای مشابه یکدیگر، از روشهایی نظیر «گراف همجواری ناحیهها» (Region Adjacency Graph | RAG) استفاده میشود.
جمعبندی
قطعه بندی تصویر (بخش بندی تصویر) یکی از گامهای اساسی در پردازش تصویر محسوب میشود. حوزه قطعه بندی تصویر، یکی از شاخههای تحقیقاتی بسیار فعال در حوزه «هوش مصنوعی» (Artificial Intelligence) محسوب میشود. قطعه بندی تصویر در حوزههای بسیار زیادی از جمله بینایی کامپیوتر، تصویربرداری پزشکی، نظارت ویدئویی و ترافیک و سایر موارد کاربرد دارد.
در زبان برنامهنویسی پایتون (Python Programming Language)، کتابخانه scikit-image الگوریتمهای بسیار معروف و پرکاربردی در حوزه پردازش تصویر دیجیتال پیادهسازی کرده است. کدهایی که توسط پدیدآورندگان این کتابخانه برنامهنویسی تهیه شدهاند، از کیفیت بسیار بالایی برخوردار هستند. همچنین، این الگوریتمها توسط جامعه برنامهنویسی بسیار فعال کد نویسی شدهاند. ویژگی دیگر این کتابخانه مهم در زبان پایتون این است که استفاده از کدهای آن برای توسعه برنامههای کاربردی مرتبط با حوزه پردازش تصویر و توزیع برنامههای کاربردی توسعه داده شده در سطح وب، برای عموم آزاد است و هیچگونه محدودیتی وجود ندارد.
اگر نوشته بالا برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای دادهکاوی و یادگیری ماشین
- آموزش اصول و روشهای دادهکاوی (Data Mining)
- مجموعه آموزشهای هوش مصنوعی
- تشخیص اشیا در پایتون — راهنمای کاربردی
- پردازش تصویر در متلب — راهنمای جامع
- نقشه دانش فناوریهای هوش مصنوعی و دسته بندی آنها — راهنمای جامع
- پیاده سازی مدل دسته بندی تصاویر در پایتون — راهنمای کاربردی
- پردازش تصویر با پایتون — راهنمای کاربردی
^^