[画像処理]画像にノイズを加える

アルゴリズム

本投稿では、Pythonを用いて画像にノイズを加えていきます。

加えるノイズ

今回実装するノイズは以下の3つです。

インパルスノイズとは?

インパルスのいずは、画像処理分野で広く研究されている画像劣化のモデルであり、以下の式で定義されています。

$$ x’_{ij} = \begin{equation} \left\{ \, \begin{aligned} & n_{ij} & 確率p \\ & x_{ij} & 確率(1-p) \end{aligned} \right. \end{equation} $$

塩ごまノイズとは?

塩ごまノイズは、インパルスノイズの確率pの値が0.5の時のノイズである

$$ x’_{ij} = \begin{equation} \left\{ \, \begin{aligned} & n_{ij} & 確率0.5 \\ & x_{ij} & 確率0.5 \end{aligned} \right. \end{equation} $$

ガウシアンノイズとは?

ガウス雑音(ガウスざつおん)は正規分布(ガウス分布ともいう)と等しい確率密度関数を持つ統計的雑音[1][2]。言い換えると、ノイズがとる値がガウス分布であるということである。

wiki

ガウス確率変数をzとする確率密度関数pは以下のようになる。

$$ P_G(Z) = \frac{1}{σ\sqrt{2\pi} \\}exp(-\frac{(z-\mu)^2}{2\sigma^2}) $$

Pythonで実装

全コード

# ライブラリ読み込み
import cv2
import numpy as np
import random

class NoiseImage:
    def __init__(self):
        self.img = None

    # 画像読み込み
    def image_read(self, filename, gray=False):
        if gray == True:
            img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE)
        else:
            img = cv2.imread(filename)
        self.img = img
        return img

    # ノイズ付与関数
    def noise_in_image(self, noise_name, noise_level=0.02, rate=None, ave=0, sigma=0.01):
        if noise_name == "impulse":
            noise_img = impulse(self.img, noise_level, rate)
        elif noise_name == "salt&pepper":
            noise_img = salt_and_pepper(self.img, noise_level)
        elif noise_name == "gaussian":
            noise_img = gaussian(self.img, ave, sigma)

        return noise_img

# インパルスノイズ
def impulse(img, noise_level, rate=0.5):
    img_size = (img.shape[0]) * (img.shape[1])
    noise_sum = int(img_size * noise_level)
    noise_xy_random = random.sample(range(1, img_size+1), k=noise_sum)

    if len(img.shape) == 2: # グレースケール用
        noise_img = img
        for i in range(len(noise_xy_random)):
            noise_fig = np.random.choice([0, 255], p=[rate, 1-rate])
            x = int((noise_xy_random[i] - 1)  / img.shape[0])
            y = (noise_xy_random[i] - 1) - (img.shape[1] * x)
            noise_img[x][y] = noise_fig

    elif len(img.shape) == 3: # カラー用
        channels = 3
        noise_img = img
        for i in range(len(noise_xy_random)):
            noise_fig = np.random.choice([0, 255], p=[rate, 1-rate])
            x = int((noise_xy_random[i] - 1)  / img.shape[0])
            y = (noise_xy_random[i] - 1) - (img.shape[1] * x)
            for j in range(channels):
                noise_img[x][y][j] = noise_fig
    return noise_img

# 塩ごまノイズ
def salt_and_pepper(img, noise_level):
    rate = 0.5
    img_size = (img.shape[0]) * (img.shape[1])
    noise_sum = int(img_size * noise_level)
    noise_xy_random = random.sample(range(1, img_size+1), k=noise_sum)

    if len(img.shape) == 2: # グレースケール用
        for i in range(len(noise_xy_random)):
            noise_img = img
            noise_fig = np.random.choice([0, 255], p=[rate, 1-rate])
            x = int((noise_xy_random[i] - 1)  / img.shape[0])
            y = (noise_xy_random[i] - 1) - (img.shape[1] * x)
            noise_img[x][y] = noise_fig

    elif len(img.shape) == 3: # カラー用
        channels = 3
        noise_img = img
        for i in range(len(noise_xy_random)):
            noise_fig = np.random.choice([0, 255], p=[rate, 1-rate])
            x = int((noise_xy_random[i] - 1)  / img.shape[0])
            y = (noise_xy_random[i] - 1) - (img.shape[1] * x)
            for j in range(channels):
                noise_img[x][y][j] = noise_fig
    return noise_img

# ガウシアンノイズ
def gaussian(img, ave=0, sigma=0.01):
    noise = np.random.normal(0, sigma, np.shape(img))
    img = img + noise

    img[img > 255] = 255
    img[img < 0] = 0
    noise_img = img.astype(np.uint8)
    return noise_img


if __name__ == "__main__":
    # 画像読み込み
    filename = "Lenna.bmp"
    noise_class = NoiseImage()
    img = noise_class.image_read(filename, gray=True)
    # ノイズ付与
    ## インパルスノイズ
    # noise_img = noise_class.noise_in_image("impulse", noise_level=0.06, rate=0.8)
    # cv2.imwrite("LennaImpulseNoise.bmp", noise_img)
    ## 塩ごまノイズ
    noise_img = noise_class.noise_in_image("salt&pepper")
    cv2.imwrite("LennaSaltPepperNoise.bmp", noise_img)
    ## ガウシアンノイズ
    # noise_img = noise_class.noise_in_image("gaussian", ave=0, sigma=30)
    # cv2.imwrite("LennaGausNoise.bmp", noise_img)

出力結果

次の画像は、ノイズを加える前のオリジナル画像です。

次にノイズを付与した画像です。

左から、インパルスノイズ塩ごまノイズガウシアンノイズです。

参考文献

コメント

タイトルとURLをコピーしました