• OpenCV4(C++)—— 图像噪声与图像滤波



    前言

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


    一、图像噪声

    1、椒盐噪声

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

    大致步骤:

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

    代码如下(示例):

    #include 
    #include 
    #include  
    
    using 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和列索引col
            int row = distribution(gen) * image.rows;
            int col = distribution(gen) * image.cols;
    
            // 2、确定噪声的种类
            // 3、修改像素灰度值
            if (image.channels() == 1)  // 灰度图像
            {
                // 使用distribution(gen) < 0.5生成一个随机数,如果该随机数小于0.5,则将像素值设置为0,否则设置为255
                image.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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    在这里插入图片描述

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

    2、高斯噪声

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

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

    代码如下(示例):

    #include 
    #include 
    #include  
    using 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和标准差stddev
    
        cv::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相加,偏置为0
    
        noisyImage.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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    在这里插入图片描述

    在这里插入图片描述


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

    二、图像滤波

    图像滤波的简单介绍:Link

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

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

    此外,滤波完后的图像往往整体看起来相比之前更加模糊,所以图像滤波也称图像模糊或图像平滑。

    注:滤波器(即卷积核)是一个矩阵形式,而矩阵可分成一个列向量和一个行向量相乘。
    在这里插入图片描述
    所以滤波操作也可以分开进行。在高斯滤波中经常应用,分为X方向滤波和Y方向滤波。

  • 相关阅读:
    Linux上搭建ElasticSearch-8.x集群以及安装Kibana(保姆级安装教程)
    Servlet学习笔记
    day09-计算机网络参考模型
    2022年全国最新消防设施操作员(高级消防设施操作员)真题题库及答案
    环境保护监测系统
    Flutter之Json序列化
    【毕业设计】13-基于单片机的锂电池管理系统(原理图+源码+仿真工程+论文)
    北京地区图片
    “数聚瑞安 · 创新未来”中国·瑞安第四届创新创业大赛角逐火热,初赛结果已公布!
    Java基础知识总结(2023版)
  • 原文地址:https://blog.csdn.net/qq_43199575/article/details/133788822