文章目录

  • 前言
    • 一、图像噪声
    • 1、椒盐噪声
    • 2、高斯噪声
  • 二、图像滤波

前言

图像噪声是图像在摄取或传输时所受的随机信号干扰,表现为图像信息或者像素亮度的随机变化。目前最常见的两者噪声是椒盐噪声和高斯噪声。


一、图像噪声

1、椒盐噪声

  椒盐噪声又被称作脉冲噪声,它会随机改变图像中的像素值,是由相机成像、图像传输、解码处理等过程产生的黑白相间的亮暗点噪声,其样子就像在图像上随机的撒上一些盐粒和黑椒粒,因此被称为椒盐噪声。
 OpenCV中没有专门增加椒盐噪声的函数,可根据原理自行编写。

大致步骤:

  1. 确定添加椒盐噪声的位置。椒盐噪声会随机出现在图像中任何一个位置,可以通过随机数函数生成两个随机数,分别用于确定椒盐噪声产生的行和列。
  2. 确定噪声的种类。不仅椒盐噪声的位置是随机的,噪声点是黑色的还是白色的也是随机的,因此可以再次生成随机数,通过判断随机数的奇偶性确定该像素是黑色噪声点还是白色噪声点。
  3. 修改图像像素灰度值。判断图像通道数,通道数不同的图像中像素表示白色的方式也不相同。也可以根据需求只改变多通道图像中某一个通道的数值。

代码如下(示例):

#include #include #includeusing namespace std;void addSaltAndPepperNoise(cv::Mat& image, double noiseRatio){// 生成随机数并初始化std::random_device rd;// 获取随机数种子std::mt19937 gen(rd()); // 使用mt19937作为随机数引擎std::uniform_real_distribution<> distribution(0.0, 1.0);// 创建随机数分布器,将用于生成介于0.0和1.0之间的随机数// 计算图像中的像素总数和要添加噪声的像素数量int numPixels = image.total();int numNoisePixels = static_cast<int>(numPixels * noiseRatio);for (int i = 0; i < numNoisePixels; ++i){// 1、确定添加椒盐噪声的位置:每次迭代中,代码生成两个随机数,即随机的行索引row和列索引colint row = distribution(gen) * image.rows;int col = distribution(gen) * image.cols;// 2、确定噪声的种类// 3、修改像素灰度值if (image.channels() == 1)// 灰度图像{// 使用distribution(gen) < 0.5生成一个随机数,如果该随机数小于0.5,则将像素值设置为0,否则设置为255image.at<uchar>(row, col) = (distribution(gen) < 0.5) ? 0 : 255;}else if (image.channels() == 3)// 彩色图像{// 如果图像是彩色图像,则在选定位置处创建一个cv::Vec3b类型的向量image.at<cv::Vec3b>(row, col) = cv::Vec3b((distribution(gen) < 0.5) ? 0 : 255,(distribution(gen) < 0.5) ? 0 : 255,(distribution(gen) < 0.5) ? 0 : 255);}}}int main(){cv::Mat img0 = cv::imread("C:/Users/Opencv/temp/wn.png", 0);cv::imshow("原图", img0);// 添加椒盐噪声double noiseRatio = 0.05;addSaltAndPepperNoise(img0, noiseRatio);cv::imshow("椒盐噪声", img0);cv::waitKey(0);cv::destroyAllWindows();return 0;}


从结果来看,灰度图像加上椒盐噪声,就是多了黑、白两种点。彩色图像加椒盐噪声,多了黑、白、红、蓝、绿等多种点,因为示例代码中,每个通道的像素都是随机的,可以是[0,0,0]、[255,0,0]、[0,255,255]等,若只想要黑、白点,就设定三个通道的随机数一样即可。

2、高斯噪声

  高斯噪声又称为正态噪声,在噪声图像的统计直方图上呈正态分布。OpenCV4中同样没有专门为图像添加高斯噪声的函数,根据原理自行编写。
 椒盐噪声是在随机位置上生成0或255这种像素点进行替换,而高斯噪声是在区域内,即所有像素点,进行像素叠加,所以大致步骤:

  1. 首先需要创建一个与图像尺寸、数据类型以及通道数相同的Mat类变量
  2. 在该Mat类变量产生符合高斯分布的随机数
  3. 将原图像和含有高斯分布的随机数矩阵按一定权重相加

代码如下(示例):

#include #include #includeusing namespace std;void addGaussianNoise(cv::Mat& image, double mean, double stddev){std::random_device rd;std::mt19937 gen(rd());std::normal_distribution<> distribution(mean, stddev); // 创建一个正态分布对象distribution,用于生成高斯分布的随机数,其参数为均值mean和标准差stddevcv::Mat noise;if (image.channels() == 1) {noise = cv::Mat(image.size(), CV_32F);for (int i = 0; i < image.rows; i++) {for (int j = 0; j < image.cols; j++) {float& pixel = noise.at<float>(i, j);pixel = distribution(gen);}}}else if (image.channels() == 3) {noise = cv::Mat(image.size(), CV_32FC3);for (int i = 0; i < image.rows; i++) {for (int j = 0; j < image.cols; j++) {cv::Vec3f& pixel = noise.at<cv::Vec3f>(i, j);pixel[0] = distribution(gen);pixel[1] = distribution(gen);pixel[2] = distribution(gen);}}}cv::Mat noisyImage;image.convertTo(noisyImage, noise.type());cv::addWeighted(noisyImage, 1.0, noise, 1.0, 0.0, noisyImage); // 按照权重系数1:1相加,偏置为0noisyImage.convertTo(image, image.type());}int main(){cv::Mat img0 = cv::imread("C:/Users/Opencv/temp/wn.png",0);cv::imshow("原图", img0); // 添加高斯噪声double mean = 10;double stddev = 20;addGaussianNoise(img0, mean, stddev);cv::imshow("高斯噪声", img0);cv::waitKey(0);cv::destroyAllWindows();return 0;}


注:目前OpenCV中虽然没有直接进行添加噪声的函数,但其他库是有的,如torchvision的transforms,skimage库的skimage.util.random_noise(image, mode=‘gaussian’, seed=None, clip=True, **kwargs)等。

二、图像滤波

图像滤波的简单介绍:Link

OpenCV中虽然没有直接进行添加噪声的函数,但提供了滤波函数。图像滤波大致分为两种:线性滤波和非线性滤波。
  线性滤波中有方框滤波、均值滤波、高斯滤波。因为进行的是类似于卷积的线性计算,所以定义为线性滤波。
 非线性滤波中有中值滤波和双边滤波。

使用方式就不介绍了,比较简单。一般高斯噪声用线性滤波处理,椒盐噪声用非线性滤波处理

注:滤波器(即卷积核)是一个矩阵形式,而矩阵可分成一个列向量和一个行向量相乘。

所以滤波操作也可以分开进行。在高斯滤波中经常应用,分为X方向滤波和Y方向滤波。