查看原文
其他

OpenCV实战 | 噪声生成与图像加噪声

gloomyfish OpenCV学堂 2020-02-04

点击上方蓝字关注我们

微信公众号:OpenCV学堂

关注获取更多计算机视觉与深度学习知识


引子

2020年第一篇技术文章,写点有意思的,图像噪声有美感的!

噪声图像生成

随机噪声

首先看两张图片,大小均为512* 512个像素, 第一张是纯蓝色

第二张是加有随机噪声的蓝色

产生随机噪声的算法简单的不能再简单了

加速RGB图像的RED与GREEN通道数据为零,蓝色通道通过0~255范围之间随机数生成即可得到,代码演示如下:

1Mat src = Mat::zeros(Size(512512), CV_8UC3);
2src = Scalar(25500);
3imshow("input", src);
4imwrite("D:/blue.png", src);
5// noise with blue
6int w = src.cols;
7int h = src.rows;
8for (int row = 0; row < h; row++) {
9    for (int col = 0; col < w; col++) {
10        int pv = 255 * rand() / (RAND_MAX + 1);
11        src.at<Vec3b>(row, col)[0] = pv;
12    }
13}
14imshow("random noise", src);

其中rand()是C++的随机函数,最大值为RAND_MAX,要得到0~1之间的随机值生成可以表示为:rand()/(RAND_MAX + 1), 如要要0~255范围之间则表示像素值 pixel = 255*rand()/(RAND_MAX + 1)。


如何给一张已经有的图像加上噪声,很容易,OpenCV提供了一个高斯分别随机数生成的函数:

1void cv::randn(
2    InputOutputArray dst,    
3    InputArray mean,    
4    InputArray stddev     
5)

dst:表示输入的Mat对象,同时也是输出

mean:表示分布的均值

stddev:表示标准方差

给图像添加高斯噪声的代码如下:

1Mat image = imread("D:/images/test.png");
2imshow("image", image);
3Mat noiseAdd = Mat::zeros(image.size(), image.type());
4randn(noiseAdd, (151515), (303030));
5add(image, noiseAdd, image);
6imshow("noiseAdd", image);


运行结果如下:

更好玩的噪声生成

你没看错,噪声有时候也可以很美的,很好玩的,请看下面这张图,也是基于噪声生成的。

前面生成噪声的方法都太过简单粗暴,都是线性计算,这里我们希望噪声可以周期性的变化,有一定的规律呈现,同时符合人眼的感官视觉变化曲线,不会觉得那么生硬。所以我们需要一个周期性函数,这里选择cos,在[0, PI]区间递减,在[PI, 2PI]区间递增,取值范围在[-1, 1]之间。但是我们像素值在0~255之间,缩放随机数可以取值范围为0~1之间,生成的浮点数坐标采样线性插值,所以我们需要cos(PI+(x-x0/x1-x0) * PI) + 1, 现在计算出来的值是[0, 1]区间之内 根据插值公式最终有:

y = (y1-y0) * cos(PI + (x-x0/x1-x0) * PI) + 1 + y0

其中[x, y]代表要计算的点,周围四个采样点为:

[x-N, y-N], [x+N, y-N], [x-N, y+N], [x+N, y+N ]

运用双线性插值原理即可计算出[1, N]个每个像素点的值。其中N表示变化周期。


线性插值代码如下:

1double interpolate(double x0, double xx0, double x1, double xx1, double x) {
2    return (1.0 + cos(CV_PI +(CV_PI / (x1 - x0)) * (x - x0))) / 2.0 * (xx1 - xx0) + xx0;
3}


随机噪声可以预先计算,然后根据坐标位置直接查询即可,这样可以减少计算量,代码实现如下:

1// 初始化噪声随机数
2for (int i = 0; i< sum; i++) {
3    blue_random[i] = ((float)rand()) / (float)(RAND_MAX + 1);
4    red_random[i] = ((float)rand()) /(float) (RAND_MAX + 1);
5    green_random[i] = ((float)rand()) / (float)(RAND_MAX + 1);
6}
7
8// 查询获取噪声
9double noise(int x, int y, int colorType) {
10    if (colorType == 1) {
11        if (x < s && y < s)
12            return red_random[y * s + x];
13        else
14            return 0.0;
15    }
16    else if (colorType == 2) {
17        if (x < s && y < s)
18            return green_random[y * s + x];
19        else
20            return 0.0;
21    }
22    else {
23        if (x < s && y < s)
24            return blue_random[y * s + x];
25        else
26            return 0.0;
27    }
28}


获取每个坐标颜色代码如下:

1double getColor(int x, int y, int M, int color_type) {
2    int x0 = x - (x % M);
3    int x1 = x0 + M;
4    int y0 = y - (y % M);
5    int y1 = y0 + M;
6        // 获取噪声
7    double x0y0 = noise(x0, y0, color_type);
8    double x1y0 = noise(x1, y0, color_type);
9    double x0y1 = noise(x0, y1, color_type);
10    double x1y1 = noise(x1, y1, color_type);
11        // 双线性插值
12    double xx0 = interpolate(x0, x0y0, x1, x1y0, x);
13    double xx1 = interpolate(x0, x0y1, x1, x1y1, x);
14    double N = interpolate(y0, xx0, y1, xx1, y);
15    return N;
16}


完整的代码调用如下:

1// add art noise
2Mat noise_img = Mat::zeros(Size(s, s), CV_8UC3);
3int intervalPixels = 50// default
4w = noise_img.cols;
5h = noise_img.rows;
6for (int row = 0; row < h; row++) {
7    for (int col = 0; col < w; col++) {
8        // set random color value for each pixel
9        r = (int)(255.0 * getColor(row, col, intervalPixels, 1));
10        g = (int)(255.0 * getColor(row, col, intervalPixels, 2));
11        b = (int)(255.0 * getColor(row, col, intervalPixels, 4));
12        noise_img.at<Vec3b>(row, col)[0] = b;
13        noise_img.at<Vec3b>(row, col)[1] = g;
14        noise_img.at<Vec3b>(row, col)[2] = r;
15    }
16}
17imshow("art noise", noise_img);


可以选择变化周期与三个通道值,会生成各种颜色的噪声。更多测试结果如下:

叠加一下看看如下:

效果魔幻不/?原来噪声也可以这么玩!


 推荐阅读 

 2019原创技术文章汇总

2018年原创技术文章汇总

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存