افزودن نویز گاوسی به تصویر در پایتون

توی پردازش تصویر نویز گاوسی مثل یک بنچ‌مارک می‌مونه، استاد من که قویا اعتقاد داره  اگر در برابر نویز گاوسی مقاوم باشیم بقیه‌ی نویز‌ها (مثل نمک و فلفل و …) مشکل خاصی ایجاد نمی‌کنن، ما هم به حرفش اعتماد می‌کنیم 😉

پس بیاید در ادامه‌ی این نوشته یک مقدار نویز گاوسی در پایتون ایجاد کنیم و اونو بریزیم توی تصویر، چرا که نه؟!

نویز در تصویر دقیقا چیه؟

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

نویز گاوسی چیه؟

ایجاد نویز گوسی و افزودن آن به تصویر در Python:

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

برای ایجاد تابع تصادفی با توزیع نرمال می‌تونیم از دستور random.randn  از کتابخانه‌ی  numpy در پایتون استفاده کنیم.

For random samples from on , use:

sigma * np.random.randn(...) + mu

تعداد کانال‌های تصویر یا ۱ هست (برای تصاویر سیاه‌سفید/خاکستری) و یا ۳ (تصاویر رنگی RGB)، ما با استفاده از دستور بالا نویز تصادفیمون رو تولید می‌کنیم و اون رو به تک تک کانال‌‌های تصویر اعمال می‌کنیم:

def add_gaussian_noise(image_in, noise_sigma):
    temp_image = np.float64(np.copy(image_in))

    h = temp_image.shape[0]
    w = temp_image.shape[1]
    noise = np.random.randn(h, w) * (noise_sigma ** 2)

    noisy_image = np.zeros(temp_image.shape, np.float64)
    if len(temp_image.shape) == 2:
        noisy_image = temp_image + noise
    else:
        noisy_image[:,:,0] = temp_image[:,:,0] + noise
        noisy_image[:,:,1] = temp_image[:,:,1] + noise
        noisy_image[:,:,2] = temp_image[:,:,2] + noise

    return noisy_image

دقت کنید که تصویر نویزی ما فرمت float64 داره، و همچنین افزودن نویز ممکنه باعث شه اندازه‌ی پیکسل‌ها از محدوده ۰ تا ۲۵۵ خارج شه.

پس یک تابع دیگه هم می‌نویسیم که کارش تغییر فرمت عکس نویزی و آوردن محدوده‌ی متغیرها به بازه‌ی ۰ تا ۲۵۵ 8 هست:

def convert_to_uint8(image_in):
    temp_image = np.float64(np.copy(image_in))
    cv2.normalize(temp_image, temp_image, 0, 255, cv2.NORM_MINMAX, dtype=-1)

    return temp_image.astype(np.uint8)

بیاید همه‌چیز رو در کنار هم ببینم:

برنامه زیر یک تصویر رو می‌خونه، بهش نویز اضافه می‌کنه، تصویر نویزی رو ذخیره کرده و در نهایت نمایش میده.

#!/usr/bin/env python
# coding: utf-8

import cv2
import numpy as np

# این تابع کارش نمایش تصویر و صبر کردنه
def show_image_and_wait(title, image, resize_scale=None):
    if resize_scale:
        disp_img = cv2.resize(image, (0, 0), None, resize_scale, resize_scale)
    else:
        disp_img = image
    key = 0
    while True:
        cv2.imshow(title, disp_img)
        
        key = cv2.waitKey(1) & 0xFF
        if key == 27:
            print('<ESC> pressed')
            break
        elif key == ord('q'):
            print('<q> pressed')
            break
            
        if cv2.getWindowProperty(title ,cv2.WND_PROP_VISIBLE) < 1:    
            print('Close (X) button clicked')            
            break  
    cv2.destroyWindow(title)
# توی پست قبلی در مورد این تابع مفصلا صحبت کردم
# کارش کنار هم قرار دادن دوتا تصویر هست، تا بهتر بتونیم اصر نویز رو ببینیم
def concat_images(img1, img2, direction='H'):
    assert img1.shape == img2.shape , "Both images MUST be in same shape!"
    if direction == 'H':
        new_img = cv2.hconcat([img1, img2])
    elif direction == 'V':
        new_img = cv2.vconcat([img1, img2])
    else:
        print('Plese use [V] or [H] for direction')
    return new_img

# تابع نویز گاوسی
def add_gaussian_noise(image_in, noise_sigma):
    temp_image = np.float64(np.copy(image_in))

    h = temp_image.shape[0]
    w = temp_image.shape[1]
    noise = np.random.randn(h, w) * (noise_sigma ** 2)

    noisy_image = np.zeros(temp_image.shape, np.float64)
    # تعداد کانال‌های تصویر رو چک می‌کنیم
    if len(temp_image.shape) == 2:
        noisy_image = temp_image + noise
    else:
        noisy_image[:,:,0] = temp_image[:,:,0] + noise
        noisy_image[:,:,1] = temp_image[:,:,1] + noise
        noisy_image[:,:,2] = temp_image[:,:,2] + noise

    return noisy_image

# تبدیل فرمت اعداد تصویر
def convert_to_uint8(image_in):
    temp_image = np.float64(np.copy(image_in))
    cv2.normalize(temp_image, temp_image, 0, 255, cv2.NORM_MINMAX, dtype=-1)

    return temp_image.astype(np.uint8)

def main():
    # عکس اصلی می‌خونیم
    original_image = cv2.imread("Can't sleep, Gonna die.jpg", cv2.IMREAD_UNCHANGED)
    # بهش نویز اضافه می‌کنیم
    noisy_sigma = 10
    noisy_image = add_gaussian_noise(original_image, noisy_sigma)
    # تصویر نویزی رو ذخیره می‌کنیم
    noisy_filename = "Can't sleep, Gonna die_noise_" + str(noisy_sigma)
    cv2.imwrite(noisy_filename + ".jpg", convert_to_uint8(noisy_image))
     
    # تصویر اصلی و نویزی رو در کنار هم قرار بدیم
    disp_img = concat_images(convert_to_uint8(noisy_image), original_image)
    # چی بهتر از قرار دادن یک مقدار اصلاعات روی تصویر؟
    cv2.putText(disp_img,'Gaussian noise sigma:  {0}'.format(noisy_sigma), (100,40), cv2.FONT_HERSHEY_SIMPLEX, 0.70, (0, 255, 0), 2)
    cv2.putText(disp_img,'Original Image without noise'.format(noisy_sigma), (600,40), cv2.FONT_HERSHEY_SIMPLEX, 0.70, (0, 255, 0), 2)
    # تصویر جدید رو نمایش می‌دیم
    show_image_and_wait(noisy_filename, disp_img) 

if __name__ == "__main__":
    main()




پ.ن: اگر در مورد قرار دادن دوتا تصویر در کنار هم سوال دارید +اینجا در موردش صحبت کردم.

منابع:

https://docs.scipy.org/doc/numpy/reference/generated/numpy.random.randn.html

http://math-cs.aut.ac.ir/~shamsi/kh/06-imageProcessing-NOISE%20-%20Copy.pdf

http://www.magikcode.com/?p=240


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

You may also like

۱ دیدگاه

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *