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

文章目录


前言

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


一、图像噪声

1、椒盐噪声

椒盐噪声又被称作脉冲噪声,它会随机改变图像中的像素值,是由相机成像、图像传输、解码处理等过程产生的黑白相间的亮暗点噪声,其样子就像在图像上随机的撒上一些盐粒和黑椒粒,因此被称为椒盐噪声。

OpenCV中没有专门增加椒盐噪声的函数,可根据原理自行编写。

大致步骤:

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

代码如下(示例):

c 复制代码
#include <opencv2/opencv.hpp>
#include <random>
#include<iostream>  

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;
}

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

2、高斯噪声

高斯噪声又称为正态噪声,在噪声图像的统计直方图上呈正态分布。OpenCV4中同样没有专门为图像添加高斯噪声的函数,根据原理自行编写。

椒盐噪声是在随机位置上生成0或255这种像素点进行替换,而高斯噪声是在区域内,即所有像素点,进行像素叠加,所以大致步骤:

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

代码如下(示例):

c 复制代码
#include <opencv2/opencv.hpp>
#include <random>
#include<iostream>  
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;
}

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

二、图像滤波

图像滤波的简单介绍:Link

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

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

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

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

相关推荐
s_little_monster23 分钟前
【QT】QT入门
数据库·c++·经验分享·笔记·qt·学习·mfc
Yingye Zhu(HPXXZYY)31 分钟前
洛谷 P11045 [蓝桥杯 2024 省 Java B] 最优分组
c++·蓝桥杯
三玖诶40 分钟前
第一弹:C++ 的基本知识概述
开发语言·c++
木向2 小时前
leetcode42:接雨水
开发语言·c++·算法·leetcode
sukalot2 小时前
windows C++-创建基于代理的应用程序(下)
c++
labuladuo5202 小时前
AtCoder Beginner Contest 372 F题(dp)
c++·算法·动态规划
DieSnowK2 小时前
[C++][第三方库][httplib]详细讲解
服务器·开发语言·c++·http·第三方库·新手向·httplib
StrokeAce4 小时前
linux桌面软件(wps)内嵌到主窗口后的关闭问题
linux·c++·qt·wps·窗口内嵌
家有狸花7 小时前
VSCODE驯服日记(三):配置C++环境
c++·ide·vscode