随机噪声
首先看两张图片,大小均为512* 512个像素, 第一张是纯蓝色
第二张是加有随机噪声的蓝色
加速RGB图像的RED与GREEN通道数据为零,蓝色通道通过0~255范围之间随机数生成即可得到,代码演示如下:
1Mat src = Mat::zeros(Size(512, 512), CV_8UC3);
2src = Scalar(255, 0, 0);
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 9 for (int col = 0; col 10 int pv = 255 * rand() / (RAND_MAX + 1);
11 src.at(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)
1
Mat image = imread("D:/images/test.png");
2imshow("image", image);
3Mat noiseAdd = Mat::zeros(image.size(), image.type());
4randn(noiseAdd, (15, 15, 15), (30, 30, 30));
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 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 12
return red_random[y * s + x];
13 else
14 return 0.0;
15 }
16 else if (colorType == 2) {
17 if (x 18 return green_random[y * s + x];
19 else
20 return 0.0;
21 }
22 else {
23 if (x 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;
6