画像の評価指標をいろいろ試していて、あえてノイズ混じりの品質の悪いデータを作りたいなと思いました。ライブラリっぽいものはなさそうでしたので、作った結果をメモします。
作りたいものは左の元画像に対して、右のようないわゆるごま塩ノイズが付加された画像です。

ということで、まずは下準備としてライブラリのインポートと画像の読み込みを行います。読み込む画像名は当然、自分の環境に応じて変えてください。
(全体のコードは最後に記載します)
import numpy as np import cv2 np.random.seed(0) # 任意: 再現性をもたせたい場合に設定 img = cv2.imread('IMG004.JPG')
ガウシアンノイズの作成
元画像と同サイズのノイズ画像を作成し、足し合わせることでノイズ画像を作成することにしました。ガウシアンノイズはnumpyのrandom.normal()で作ることができます。
ガウシアン分布のパラメータ (μ:ノイズの平均値とsigma:ノイズの標準偏差) 、生成するノイズの数を指定します。ごま塩ノイズを作りたい場合は、mu=0固定でsigmaの値を任意の範囲で動かせばOKです。
mu = 0 sigma = 100 noise = np.random.normal(mu, sigma, img.shape)
ノイズ画像の生成
画像にノイズを足し合わせるときは、0~255の8bitの範囲外にぶっ飛んでしまうことを想定し、マイナス値を含む広い値を取る型に変えておきます。
足し合わせたあとに、0~255の範囲へのclipと型変換をして、元通り8bitにします。
# ノイズを付加して8bitの範囲にクリップ noisy_img = img.astype(np.float64) + noise noisy_img = np.clip(noisy_img, 0, 255).astype(np.uint8)
結果
sigmaの値を変えて何パターンか試してみました。すべて左が元画像、右がノイズ付加画像です。sigmaの値が大きくなるにつれて、ノイズも激しくなっていることがわかります。
sigma=10

sigma=100

sigma=255

また、μを変えた場合も見てみました。
sigma=0の場合は、μだけ画素値がシフトして明るさが変化しています。
μ=100

μ=-100

全体コード
とりあえず、全体の簡単なコードは以下です。
μとsigma、元画像の配列を受け取ってノイズ画像を返すような関数にしました。
import numpy as np import cv2 np.random.seed(0) def add_noise(img, mu=0, sigma=100): # 画素数xRGBのノイズを生成 noise = np.random.normal(mu, sigma, img.shape) # ノイズを付加して8bitの範囲にクリップ noisy_img = img.astype(np.float64) + noise noisy_img = np.clip(noisy_img, 0, 255).astype(np.uint8) return noisy_img mu = 0 sigma = 100 img = cv2.imread('IMG004.JPG') noisy_img = add_noise(img, mu, sigma) cv2.imwrite(f'noisy_img_mu{mu}_sigma{sigma}.png', noisy_img)