امروزه با کمک پردازش تصویر و هوش مصنوعی میتوان تحلیلهای عمیقی انجام داد. تشخیص چهره، تشخیص چشم، تشخیص خودرو و … از این دسته از تحلیلها میباشند. اما پردازش تصویر چگونه انجام میگیرد یا چگونه میتوان آن را پیاده سازی کرد. امروز در همین خصوص، وارد مبحث آستانه گذاری adaptive تصاویر در OpenCV خواهیم شد.
ماژول opencv
Opencv یکی از ماژولهای پردازش تصویر و هوش مصنوعی میباشد. با کمک این ماژول میتوان تصاویر را دریافت و بسیاری از عملیاتهای پردازش تصویر را پیاده سازی کرد. جالب است بدانید با opencv میتوان تشخیص چهره، تشخیص چشم و یا حتی تشخیص اعداد را نیز انجام داد. علاوه بر تصاویر، پردازش ویدئو نیز میتوان با کمک این ماژول انجام داد. در این مقاله، آستانهگذاری adaptive تصاویر را با کمک OPENCV و زبان برنامهنویسی پایتون پیادهسازی خواهیم کرد. البته بعضی از قسمتها به موجب نیاز، از ماژول Numpy نیز استفاده میگردد.
آستانه گذاری تصویر چیست
آستانه گذاری تصویر یکی از سادهترین روشهای ناحیهبندی تصویر است که در آن مقدار پیکسلهای یک تصویر با توجه به آستانه تعیین شده، به صفر یا مقدار ماکزیمم (255 یا 0) تغییر پیدا میکنند. در آستانهگذاری، تصویر دارای دو ناحیه میباشد. (پیکسلهای بزرگتر از آستانه و کوچکتر از آن).
در این آموزش با کمک ماژول opencv در پایتون به پیاده سازی آستانهگذاری خواهیم پرداخت. در جلسات گذشته چندین روش آستانهگذاری را یاد گرفتیم. ابتدا مروری بر روشهای جلسه گذشته میکنیم:
- cv2.THRESH_BINARY: اگر مقدار پیکسل بیشتر از آستانه باشد، مقدار آن 255 و در غیر اینصورت به 0(سیاه رنگ) تغییر میکند.
- cv2.THRESH_BINARY_INV: معکوس روش بالا می باشد.
- THRESH_TRUNC: اگر مقدار پیکسل بیشتر از آستانه باشد، مقدار آن برابر با آستانه و در غیر اینصورت مقدار آن تغییری پیدا نخواهد کرد.
- cv.THRESH_TOZERO: تمامی پیکسلهای کمتر از آستانه برابر با صفر میشوند.
- cv.THRESH_TOZERO_INV: معکوس روش قبل است.
علاوهبر روشهای بالا روش OTSU نیز توضیح داده شد. این روش به صورت اتوماتیک مقدار آستانه را پیدا میکند. توجه کنید که در روشهای بالا، مقدار آستانه به صورت دستی(توسط ما) تعیین میگردد اما روش OTSU به صورت اتوماتیک (با کمک هیستوگرام و واریانس) برای هر تصویر مقدار آستانه را بدست میآورد.
چرا آستانه گذاری adaptive
در تمامی روشهای توضیح داده شده یک مشکل اساسی وجود دارد. ما برای تمامی تصویر یک مقدار آستانه را داریم و این باعث میشود پس از اعمال این روشها، خروجی مورد نظر ما بدست نیاید. به تصویر زیر دقت کنید:
خروجی بالا پس از اعمال آستانهگذاری Threshold Binary میباشد. قسمت پایین به طور کلی مشکی شده و متن کتاب از بین رفته است.
تصویر بالا پس از اعمال آستانهگذاری adaptive است. تمامی متن کتاب از پس زمینه جداسازی شده و براحتی قابل شناسایی هستند. اما چگونه؟
آستانه گذاری adaptive چیست
مشکلی که در قسمت قبل توضیح دادیم به این دلیل است که برای تمام تصویر یک مقدار آستانه تعیین میشود. ایده آستانهگذاری adaptive به این صورت است که تصویر را به زیربخشهای (subregion) مختلف تقسیم کنیم. هر کدام از این زیربخشها مقدار آستانه متفاوتی خواهند داشت. به طور کلی این روش به ما میگوید که پیکسلهایی که در کنار هم هستند و یا در همسایگی هم قرار دارند مقدار آستانه آنها مشابه یکدیگر است.
در این مقاله به اثبات ریاضی روشهای adaptive نخواهیم پرداخت. اما توضیح مختصری در مورد روش آن خواهیم داد. در opencv دو روش Adaptive پیاده سازی شده است:
- cv2.ADAPTIVE_THRESH_MEAN_C: این روش بر اساس میانگین پیکسل همسایهها، مقدار آستانه را در هر زیر بخش تعیین میکند.
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C: مقدار آستانه با استفاده از حاصل جمع وزن گائوسی همسایهها بدست میآید.
آمادهسازی تصویر
ما قبل از هر اقدامی نیاز است ماژولهای مورد نیاز را فراخوانی نماییم:
import cv2
import numpy as np
در این قسمت تصویر ورودی را ابتدا میخوانیم:
image = cv2.imread('codegate.jpg',0)
cv2.imshow("Original", image)
تصویر ورودی به صورت زیر میباشد:
تصویر ورودی یک صفحه کتاب میباشد. این را تصویر به صورت grayscale خواندیم.
پیاده سازی آستانه گذاری adaptive
برای آستانهگذاری adaptive، ماژول OpenCV تابع adaptiveThreshold را پیادهسازی کرده است. این تابع ورودیهای زیر را دریافت میکند:
- تصویر ورودی (باید grayscale باشد)
- مقدار ماکزیمم پیکسل یا maxVal
- روش adaptive که بین cv2.ADAPTIVE_THRESH_MEAN_C یا cv2.ADAPTIVE_THRESH_GAUSSIAN_C انتخاب میشود.
- روش آستانهگذاری یا thresholdingTechnique
- سایز بلاک: سایز زیر بخشها (پیکسلهای همسایه) در این قسمت تعیین میشود. بین اعداد 3،5،7 و … (اعداد فرد) مشخص میگردد.
- مقدار ثابت یا Constant: این مقدار از حاصل میزان آستانه بدست آمده در هر زیربخش کم میشود.
اکنون میخواهیم روش adapting را پیادهسازی کنیم. کد زیر را ببینید:
thresh = cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 3, 5)
cv2.imshow("Adaptive Mean Thresholding", thresh)
در کد بالا تابع adaptiveThreshold را با ورودیهای زیر صدا زدهایم:
- image (تصویر ورودی)
- عدد 255 (مقدار ماکزیمم پیکسل)
- cv2.ADAPTIVE_THRESH_MEAN_C: میانگین همسایهها را برای روش adaptive در نظر گرفتهایم.
- cv2.THRESH_BINARY (روش آستانهگذاری)
- عدد 3 (سایز بلاک): زیربخشهای 3*3 در تصویر برای آستانهگذاری ایجاد میشود
- عدد 5 (مقدار ثابت)
همچنین تابع adaptiveThreshold در خروجی، پیکسلهای تصویر، بعد از اعمال آستانهگذاری(متغیر thresh) را به ما میدهد. خروجی این قسمت به صورت زیر است:
همین تصویر را با روش OTSU بررسی میکنیم:
th2 = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.imshow("Otsu's Thresholding", th2)
خروجی کد بالا به صورت زیر است:
تفاوت دو خروجی گویای مطلب میباشد. روش adaptive کارآمدتر از روشهای قبلی آستانهگذاری میباشد.