پردازش تصویر در OpenCV
هموارسازی تصاویر (Smoothing Images)
هدف#
یادگیری:
- محوسازی تصاویر با فیلترهای مختلف پایینگذر (Low Pass Filter)
- اعمال فیلترهای دلخواه بر روی تصاویر (کانولوشن دوبعدی)
کانولوشن دوبعدی (فیلترسازی تصویر)#
همانند سیگنالهای یکبعدی، تصاویر نیز میتوانند با انواع فیلترهای پایینگذر (LPF)، بالاگذر (HPF) و غیره فیلتر شوند. LPF در حذف نویز و محوسازی تصاویر کمک میکند. فیلترهای HPF در یافتن لبهها در تصاویر مفید هستند.
OpenCV تابعی به نام cv.filter2D() برای کانولوشن یک کرنل با یک تصویر فراهم میکند. به عنوان مثال، یک فیلتر میانگینگیر را بر روی یک تصویر امتحان میکنیم. کرنل یک فیلتر میانگینگیر 5x5 به صورت زیر خواهد بود:
این عملیات به این صورت کار میکند: این کرنل را بالای یک پیکسل نگه دارید، تمام ۲۵ پیکسل زیر این کرنل را جمع کنید، میانگین بگیرید و پیکسل مرکزی را با مقدار میانگین جدید جایگزین کنید. این عملیات برای تمام پیکسلهای تصویر ادامه مییابد. این کد را امتحان کنید و نتیجه را بررسی کنید:
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('opencv_logo.png')
assert img is not None, "file could not be read, check with os.path.exists()"
kernel = np.ones((5,5),np.float32)/25
dst = cv.filter2D(img,-1,kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dst),plt.title('Averaging')
plt.xticks([]), plt.yticks([])
plt.show()
نتیجه:

محوسازی تصویر (Image Blurring / Image Smoothing)#
محوسازی تصویر (Image blurring) با کانولوشن تصویر با یک کرنل فیلتر پایینگذر به دست میآید. برای حذف نویز مفید است. در واقع محتوای فرکانس بالا (مثل: نویز، لبهها) را از تصویر حذف میکند. بنابراین لبهها در این عملیات کمی محو میشوند (روشهای محوسازیای هم وجود دارند که لبهها را محو نمیکنند). OpenCV چهار نوع اصلی از تکنیکهای محوسازی را ارائه میدهد.
۱. میانگینگیری (Averaging)#
این کار با کانولوشن یک تصویر با یک فیلتر باکس نرمالیزهشده انجام میشود. به سادگی میانگین تمام پیکسلهای زیر ناحیه کرنل را میگیرد و عنصر مرکزی را جایگزین میکند. این کار توسط تابع cv.blur() یا cv.boxFilter() انجام میشود. برای جزئیات بیشتر درباره کرنل به مستندات مراجعه کنید. باید عرض و ارتفاع کرنل را مشخص کنیم. یک فیلتر باکس نرمالیزهشده 3x3 به صورت زیر خواهد بود:
یک نمونه آزمایشی با کرنل اندازه 5x5 را در زیر ببینید:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('opencv-logo-white.png')
assert img is not None, "file could not be read, check with os.path.exists()"
blur = cv.blur(img,(5,5))
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()
نتیجه:

۲. محوسازی گاوسی (Gaussian Blurring)#
در این روش، به جای فیلتر باکس، از یک کرنل گاوسی (Gaussian kernel) استفاده میشود. این کار با تابع cv.GaussianBlur() انجام میشود. باید عرض و ارتفاع کرنل را مشخص کنیم که باید مثبت و فرد باشد. همچنین باید انحراف معیار (standard deviation) در جهتهای X و Y، به ترتیب sigmaX و sigmaY را مشخص کنیم. اگر فقط sigmaX مشخص شود، sigmaY برابر sigmaX در نظر گرفته میشود. اگر هر دو صفر داده شوند، از اندازه کرنل محاسبه میشوند. محوسازی گاوسی در حذف نویز گاوسی از یک تصویر بسیار مؤثر است.
اگر بخواهید، میتوانید یک کرنل گاوسی با تابع cv.getGaussianKernel() ایجاد کنید.
کد بالا میتواند برای محوسازی گاوسی تغییر یابد:
blur = cv.GaussianBlur(img,(5,5),0)
نتیجه:

۳. محوسازی میانه (Median Blurring)#
در اینجا، تابع cv.medianBlur() میانه تمام پیکسلهای زیر ناحیه کرنل را میگیرد و عنصر مرکزی با این مقدار میانه جایگزین میشود. این روش در برابر نویز نمک و فلفل (salt-and-pepper noise) در یک تصویر بسیار مؤثر است. جالب است که در فیلترهای بالا، عنصر مرکزی یک مقدار تازه محاسبهشده است که ممکن است یک مقدار پیکسل در تصویر یا یک مقدار جدید باشد. اما در محوسازی میانه، عنصر مرکزی همیشه با یک مقدار پیکسل موجود در تصویر جایگزین میشود. نویز را به طور مؤثری کاهش میدهد. اندازه کرنل آن باید یک عدد صحیح فرد مثبت باشد.
در این مثال، ۵۰٪ نویز به تصویر اصلی اضافه کرده و محوسازی میانه را اعمال کردم. نتیجه را بررسی کنید:
median = cv.medianBlur(img,5)
نتیجه:

۴. فیلترسازی دوطرفه (Bilateral Filtering)#
cv.bilateralFilter() در حذف نویز و در عین حال حفظ تیزی لبهها بسیار مؤثر است. اما عملیات در مقایسه با سایر فیلترها کندتر است. قبلاً دیدیم که یک فیلتر گاوسی محله پیرامون پیکسل را میگیرد و میانگین وزندار گاوسی آن را پیدا میکند. این فیلتر گاوسی تنها تابعی از فضا است، یعنی پیکسلهای مجاور در حین فیلترسازی در نظر گرفته میشوند. این روش در نظر نمیگیرد که آیا پیکسلها شدت روشنایی تقریباً یکسانی دارند یا خیر. در نظر نمیگیرد که آیا یک پیکسل یک پیکسل لبه است یا نه. بنابراین لبهها را نیز محو میکند، که این چیزی نیست که بخواهیم انجام دهیم.
فیلترسازی دوطرفه نیز یک فیلتر گاوسی در فضا را در نظر میگیرد، اما یک فیلتر گاوسی دیگر نیز وجود دارد که تابعی از اختلاف پیکسل است. تابع گاوسی فضا اطمینان حاصل میکند که فقط پیکسلهای مجاور برای محوسازی در نظر گرفته شوند، در حالی که تابع گاوسی اختلاف شدت روشنایی اطمینان حاصل میکند که فقط آن دسته از پیکسلهایی که شدت روشنایی مشابه پیکسل مرکزی دارند برای محوسازی در نظر گرفته شوند. بنابراین لبهها را حفظ میکند زیرا پیکسلهای روی لبهها تغییرات شدید شدت روشنایی دارند.
نمونه زیر استفاده از فیلتر دوطرفه را نشان میدهد (برای جزئیات آرگومانها، به مستندات مراجعه کنید).
blur = cv.bilateralFilter(img,9,75,75)
نتیجه:

همانطور که میبینید، بافت سطح از بین رفته، اما لبهها همچنان حفظ شدهاند.
منابع تکمیلی#
- جزئیات درباره فیلترسازی دوطرفه