32

我正在研究著名的冈萨雷斯“数字图像处理”的图像处理,并谈论图像恢复,很多示例都是使用计算机生成的噪声(高斯、盐和胡椒等)完成的。在 MATLAB 中有一些内置函数可以做到这一点。那么 OpenCV 呢?

4

10 回答 10

34

据我所知,没有像 Matlab 这样方便的内置函数。但只需几行代码,您就可以自己创建这些图像。

例如加性高斯噪声:

Mat gaussian_noise = img.clone();
randn(gaussian_noise,128,30);

椒盐噪声:

Mat saltpepper_noise = Mat::zeros(img.rows, img.cols,CV_8U);
randu(saltpepper_noise,0,255);

Mat black = saltpepper_noise < 30;
Mat white = saltpepper_noise > 225;

Mat saltpepper_img = img.clone();
saltpepper_img.setTo(255,white);
saltpepper_img.setTo(0,black);
于 2013-01-21T11:49:29.230 回答
19

There is function random_noise() from the scikit-image package. It has several builtin noise patterns, such as gaussian, s&p (for salt and pepper noise), possion and speckle.

Below I show an example of how to use this method

from PIL import Image
import numpy as np
from skimage.util import random_noise

im = Image.open("test.jpg")
# convert PIL Image to ndarray
im_arr = np.asarray(im)

# random_noise() method will convert image in [0, 255] to [0, 1.0],
# inherently it use np.random.normal() to create normal distribution
# and adds the generated noised back to image
noise_img = random_noise(im_arr, mode='gaussian', var=0.05**2)
noise_img = (255*noise_img).astype(np.uint8)

img = Image.fromarray(noise_img)
img.show()

enter image description here

There is also a package called imgaug which are dedicated to augment images in various ways. It provides gaussian, poissan and salt&pepper noise augmenter. Here is how you can use it to add noise to image:

from PIL import Image
import numpy as np
from imgaug import augmenters as iaa


def main():
    im = Image.open("bg_img.jpg")
    im_arr = np.asarray(im)

    # gaussian noise
    # aug = iaa.AdditiveGaussianNoise(loc=0, scale=0.1*255)

    # poisson noise
    # aug = iaa.AdditivePoissonNoise(lam=10.0, per_channel=True)

    # salt and pepper noise
    aug = iaa.SaltAndPepper(p=0.05)

    im_arr = aug.augment_image(im_arr)

    im = Image.fromarray(im_arr).convert('RGB')
    im.show()


if __name__ == "__main__":
    main()
于 2018-12-13T08:22:08.933 回答
13

向图像添加高斯、椒盐散斑和泊松噪声的简单函数

Parameters
----------
image : ndarray
    Input image data. Will be converted to float.
mode : str
    One of the following strings, selecting the type of noise to add:

    'gauss'     Gaussian-distributed additive noise.
    'poisson'   Poisson-distributed noise generated from the data.
    's&p'       Replaces random pixels with 0 or 1.
    'speckle'   Multiplicative noise using out = image + n*image,where
                n,is uniform noise with specified mean & variance.

import numpy as np
import os
import cv2

def noisy(noise_typ,image):

if noise_typ == "gauss":
        row,col,ch= image.shape
        mean = 0
        #var = 0.1
       #sigma = var**0.5
        gauss = np.random.normal(mean,1,(row,col,ch))
        gauss = gauss.reshape(row,col,ch)
        noisy = image + gauss
        return noisy
    elif noise_typ == "s&p":
        row,col,ch = image.shape
        s_vs_p = 0.5
        amount = 0.004
        out = image
        # Salt mode
        num_salt = np.ceil(amount * image.size * s_vs_p)
        coords = [np.random.randint(0, i - 1, int(num_salt))
                  for i in image.shape]
        out[coords] = 1

        # Pepper mode
        num_pepper = np.ceil(amount* image.size * (1. - s_vs_p))
        coords = [np.random.randint(0, i - 1, int(num_pepper))
                  for i in image.shape]
        out[coords] = 0
        return out
    elif noise_typ == "poisson":
        vals = len(np.unique(image))
        vals = 2 ** np.ceil(np.log2(vals))
        noisy = np.random.poisson(image * vals) / float(vals)
        return noisy
    elif noise_typ =="speckle":
        row,col,ch = image.shape
        gauss = np.random.randn(row,col,ch)
        gauss = gauss.reshape(row,col,ch)        
        noisy = image + image * gauss
        return noisy
于 2015-06-03T15:31:09.947 回答
7

可以使用 NumPy 矩阵运算以非常简单的方式添加“Salt & Pepper”噪声。

def add_salt_and_pepper(gb, prob):
    '''Adds "Salt & Pepper" noise to an image.
    gb: should be one-channel image with pixels in [0, 1] range
    prob: probability (threshold) that controls level of noise'''

    rnd = np.random.rand(gb.shape[0], gb.shape[1])
    noisy = gb.copy()
    noisy[rnd < prob] = 0
    noisy[rnd > 1 - prob] = 1
    return noisy
于 2016-04-08T08:42:12.657 回答
7
# Adding noise to the image    

import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

img = cv2.imread('./fruit.png',0)
im = np.zeros(img.shape, np.uint8) # do not use original image it overwrites the image
mean = 0
sigma = 10
cv2.randn(im,mean,sigma) # create the random distribution
Fruit_Noise = cv2.add(img, im) # add the noise to the original image
plt.imshow(Fruit_Noise, cmap='gray')

The values of mean and sigma can be altered to bring about a specific change in noise like gaussian or pepper-salt noise etc. You can use either randn or randu according to the need. Have a look at the documentation: https://docs.opencv.org/2.4/modules/core/doc/operations_on_arrays.html#cv2.randu

于 2017-10-21T06:09:45.877 回答
2

I made some change of @Shubham Pachori 's code. When reading a image into numpy arrary, the default dtype is uint8, which can cause wrapping when adding noise onto the image.

import numpy as np
from PIL import Image

"""
image: read through PIL.Image.open('path')
sigma: variance of gaussian noise
factor: the bigger this value is, the more noisy is the poisson_noised image

##IMPORTANT: when reading a image into numpy arrary, the default dtype is uint8,
which can cause wrapping when adding noise onto the image. 
E.g,  example = np.array([128,240,255], dtype='uint8')
     example + 50 = np.array([178,44,49], dtype='uint8')
Transfer np.array to dtype='int16' can solve this problem.
"""


def gaussian_noise(image, sigma):
    img = np.array(image)
    noise = np.random.randn(img.shape[0], img.shape[1], img.shape[2])
    img = img.astype('int16')
    img_noise = img + noise * sigma
    img_noise = np.clip(img_noise, 0, 255)
    img_noise = img_noise.astype('uint8')
    return Image.fromarray(img_noise)


def poisson_noise(image, factor):
    factor = 1 / factor
    img = np.array(image)
    img = img.astype('int16')
    img_noise = np.random.poisson(img * factor) / float(factor)
    np.clip(img_noise, 0, 255, img_noise)
    img_noise = img_noise.astype('uint8')
    return Image.fromarray(img_noise)
于 2019-08-14T06:54:12.863 回答
1

http://scikit-image.org/docs/dev/api/skimage.util.html#skimage.util.random_noise

skimage.util.random_noise(image, mode='gaussian', seed=None, clip=True, **kwargs)
于 2019-03-15T00:29:23.153 回答
-1
#Adding noise
[m,n]=img.shape
saltpepper_noise=zeros((m, n));
saltpepper_noise=rand(m,n); #creates a uniform random variable from 0 to 1 
for i in range(0,m):
    for j in range(0,n):
        if saltpepper_noise[i,j]<=0.5:
            saltpepper_noise[i,j]=0
        else:
            saltpepper_noise[i,j]=255
于 2015-02-06T11:12:28.507 回答
-1

although there is no built-in functions like in matlab imnoise(image,noiseType,NoiseLevel) but we can easily add required amount random valued impulse noise or salt and pepper into an image manually.

  1. to add random valued impulse noise.

    import random as r
    def addRvinGray(image,n): # add random valued impulse noise in grayscale 
        '''parameters: 
             image: type=numpy array. input image in which you want add noise.
             n:  noise level (in percentage)'''
        k=0                  # counter variable 
        ih=image.shape[0]    
        iw=image.shape[1]
        noisypixels=(ih*iw*n)/100      # here we calculate the number of pixels to be altered.
    
        for i in range(ih*iw):
            if k<noisypixels:
                    image[r.randrange(0,ih)][r.randrange(0,iw)]=r.randrange(0,256) #access random pixel in the image gives random intensity (0-255)              
                k+=1
            else:
                break
        return image
    
  2. to add salt and pepper noise

    def addSaltGray(image,n): #add salt-&-pepper noise in grayscale image
    
        k=0
        salt=True
        ih=image.shape[0]
        iw=image.shape[1]
        noisypixels=(ih*iw*n)/100
    
        for i in range(ih*iw):
             if k<noisypixels:  #keep track of noise level
                 if salt==True:
                         image[r.randrange(0,ih)][r.randrange(0,iw)]=255
                         salt=False
                 else:
                         image[r.randrange(0,ih)][r.randrange(0,iw)]=0
                         salt=True
                 k+=1
             else:
                 break
        return image
    

Note: for color images: first split image in to three or four channels depending on the input image using opencv function:

(B, G, R) = cv2.split(image)
(B, G, R, A) = cv2.split(image)

after spliting perform the same operations on all channels. at the end merge all the channels:

merged = cv2.merge([B, G, R])
return merged
于 2018-03-29T07:50:05.360 回答
-1
def add_salt_noise(src, ratio: float = 0.05, noise: list = [0, 0, 0]):
    dst = src.copy()
    import random
    shuffle_dict = {}
    i = 0
    while i < (int(dst.shape[0]*dst.shape[1] * ratio)):
        x, y = random.randint(0, dst.shape[0] - 1), random.randint(0, dst.shape[1] - 1)
        if (x, y) in shuffle_dict:
            continue
        else:
            dst[x, y] = noise
            shuffle_dict[(x, y)] = 0
            i += 1
    return dst
于 2022-02-07T12:52:04.447 回答