【OpenCV】噪声的添加和过滤

1. 简介
下面简单介绍两种图像噪声,即椒盐噪声和高斯噪声。

(1) 椒盐噪声 
椒盐噪声也称脉冲噪声,它是一种随机出现的白点或者黑点,可能是亮的区域有黑色像素或是在暗的区域有白色像素(或是两者皆有)。 
图像模拟添加椒盐噪声是通过:随机获取像素点,并设置为高亮度点和低亮度点来实现的。

(2) 高斯噪声 
高斯噪声是指概率密度函数服从高斯分布的一类噪声。 
特别的,如果一个噪声,它的幅度分布服从高斯分布,而它的功率谱密度服从均匀分布,则称这个噪声为高斯白噪声。 
高斯白噪声 功率谱密度频谱图 和 噪声幅值分布图的图片如下:

2. 代码

(1) 为图像添加椒盐噪声

//给原图像增加椒盐噪声
//图象模拟添加椒盐噪声是通过随机获取像素点,并设置为高亮度点和低亮度点来实现的
//srcImage为源图像,n为椒/盐像素点个数,返回含噪图像
Mat addSaltNoise(const Mat srcImage, int n)
{
    Mat dstImage = srcImage.clone();

    for (int k = 0; k < n; k++)
    {
        //随机取值行列,得到像素点(i,j)
        int i = rand() % dstImage.rows;
        int j = rand() % dstImage.cols;

        //图像通道判定
        if (dstImage.channels() == 1)//修改像素点(i,j)的像素值
        {
            dstImage.at<uchar>(i, j) = 255;     //盐噪声
        }
        else
        {
            dstImage.at<Vec3b>(i, j)[0] = 255;
            dstImage.at<Vec3b>(i, j)[1] = 255;
            dstImage.at<Vec3b>(i, j)[2] = 255;
        }
    }

    for (int k = 0; k < n; k++)
    {
        //随机取值行列
        int i = rand() % dstImage.rows;
        int j = rand() % dstImage.cols;
        //图像通道判定
        if (dstImage.channels() == 1)
        {
            dstImage.at<uchar>(i, j) = 0;       //椒噪声
        }
        else
        {
            dstImage.at<Vec3b>(i, j)[0] = 0;
            dstImage.at<Vec3b>(i, j)[1] = 0;
            dstImage.at<Vec3b>(i, j)[2] = 0;
        }
    }
    return dstImage;
}

(2) 为图像增加高斯噪声 方法1

此算法原理我没仔细看,但是能够成功为图像增加高斯噪声。相比来说,方法2简单得多。 
参考网址:【OpenCV】给图像添加噪声

原理:

根据Box-Muller变换原理,假设随机变量U1、U2相互独立,且均服从(0,1)之间的均匀分布,则经过下面两个式子产生的随机变量Z0,Z1服从标准高斯分布。 
 这里写图片描述
上式中Z0,Z1满足正态分布,其中均值为0,方差为1,变量U1和U2可以修改为下式: 

代码:

//生成高斯噪声
double generateGaussianNoise(double mu, double sigma)
{
    //定义小值
    const double epsilon = numeric_limits<double>::min();
    static double z0, z1;
    static bool flag = false;
    flag = !flag;
    //flag为假构造高斯随机变量X
    if (!flag)
        return z1 * sigma + mu;
    double u1, u2;
    //构造随机变量
    do
    {
        u1 = rand() * (1.0 / RAND_MAX);
        u2 = rand() * (1.0 / RAND_MAX);
    } while (u1 <= epsilon);
    //flag为真构造高斯随机变量
    z0 = sqrt(-2.0*log(u1))*cos(2 * CV_PI*u2);
    z1 = sqrt(-2.0*log(u1))*sin(2 * CV_PI*u2);
    return z0*sigma + mu;
}


//为图像添加高斯噪声
Mat addGaussianNoise(Mat &srcImag)
{
    Mat dstImage = srcImag.clone();
    int channels = dstImage.channels();
    int rowsNumber = dstImage.rows;
    int colsNumber = dstImage.cols*channels;
    //判断图像的连续性
    if (dstImage.isContinuous())
    {
        colsNumber *= rowsNumber;
        rowsNumber = 1;
    }
    for (int i = 0; i < rowsNumber; i++)
    {
        for (int j = 0; j < colsNumber; j++)
        {
            //添加高斯噪声
            int val = dstImage.ptr<uchar>(i)[j] + generateGaussianNoise(2, 0.8) * 32;
            if (val < 0)
                val = 0;
            if (val>255)
                val = 255;
            dstImage.ptr<uchar>(i)[j] = (uchar)val;
        }
    }
    return dstImage;
}

(3) 为图像增加高斯噪声 方法2(简单)

原理:用OpenCV的RNG类,为图像添加高斯噪声。

在OpenCV中,可用RNG (Random number generator) 类来产生均匀分布和正态分布(高斯分布)的随机数。

可以用RNG类的成员函数fill,来为图像添加高斯噪声。fill的原型(C++)如下:

void RNG::fill(InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=false )
1
参数意义如下:

mat:二维或多维矩阵,目前版本中,维数不能超过4。
distType:随机数的分布类型。有两种,即RNG::UNIFORM 或 RNG::NORMAL。前者表示均匀分布,后者表示正态分布(即高斯分布)。
a:分布规律参数之一。在均匀分布中表示下限(包含);在正态分布(即高斯分布)中,表示均值。
b:分布规律参数之一。在均匀分布中表示上限(包含);在正态分布(即高斯分布)中,表示标准差。
saturateRange:这个参数只对均匀分布时有用。
用fill构造一个均值为a,标准差为b的噪声矩阵(与原图像大小,类型相同),将噪声矩阵与原图像相加,即可得到含噪图像。

代码:
 

Mat anotherAddGaussianNoise(Mat &srcImg)
{
    Mat tempSrcImg = srcImg.clone();
    Mat img_output(tempSrcImg.size(), tempSrcImg.type());

    //构造高斯噪声矩阵
    Mat noise(tempSrcImg.size(), tempSrcImg.type());//创建一个噪声矩阵
    RNG rng(time(NULL));
    rng.fill(noise, RNG::NORMAL, 10, 36);//高斯分布;均值为10,标准差为36

    //将高斯噪声矩阵与原图像叠加得到含噪图像
    cv::add(tempSrcImg, noise, img_output);

    return img_output;
}

(4) 测试代码:

#include <cmath>
#include <limits>
#include <cstdlib>
#include <iostream>
#include <cvInclude.h>
#include <time.h> 

using namespace std;

Mat addSaltNoise(const Mat srcImage, int n);
Mat addGaussianNoise(Mat &srcImag);
Mat anotherAddGaussianNoise(Mat &srcImg);


int main()
{
    Mat srcImage = imread("F:/test_photo/zhongshuo.jpg");
    if (!srcImage.data)
    {
        cout << "读入图像有误!" << endl;
        system("pause");
        return -1;
    }
    imshow("原图像", srcImage);

    Mat dstSaltImage = addSaltNoise(srcImage, 3000);
    imshow("添加椒盐噪声的图像", dstSaltImage);
    imwrite("F:/test_photo/zhongshuoSalt.jpg", dstSaltImage);//存储图像

    Mat dstGaussImage = addGaussianNoise(srcImage);
    imshow("添加高斯噪声后的图像1", dstGaussImage);
    imwrite("F:/test_photo/zhongshuoGauss1.jpg", dstGaussImage);//存储图像

    Mat anotherDstGaussImage = anotherAddGaussianNoise(srcImage);
    imshow("添加高斯噪声后的图像2", anotherDstGaussImage);
    imwrite("F:/test_photo/zhongshuoGauss2.jpg", anotherDstGaussImage);//存储图像

    waitKey();
    return 0;
}

给图像添加各种噪声

OpenCv基础(一):噪声的添加和过滤

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
傅里叶变换可以将信号从时域转换到频域,因此可以用于去除正弦噪声。以下是使用OpenCV C++实现去除正弦噪声的示例代码: ```c++ #include <opencv2/opencv.hpp> #include <iostream> #include <cmath> using namespace std; using namespace cv; int main() { Mat img = imread("lena.jpg", IMREAD_GRAYSCALE); if (img.empty()) { cout << "Failed to read image!" << endl; return -1; } // Add sinusoidal noise int amplitude = 30; double frequency = 0.05; for (int i = 0; i < img.rows; i++) { for (int j = 0; j < img.cols; j++) { int value = img.at<uchar>(i, j) + amplitude * sin(2 * CV_PI * frequency * j); img.at<uchar>(i, j) = saturate_cast<uchar>(value); } } // Perform Fourier transform Mat imgFreq; dft(img, imgFreq, DFT_COMPLEX_OUTPUT); // Shift the zero-frequency component to the center of the spectrum Mat imgFreqShifted; imgFreqShifted = imgFreq.clone(); int cx = imgFreqShifted.cols / 2; int cy = imgFreqShifted.rows / 2; Mat q0(imgFreqShifted, Rect(0, 0, cx, cy)); Mat q1(imgFreqShifted, Rect(cx, 0, cx, cy)); Mat q2(imgFreqShifted, Rect(0, cy, cx, cy)); Mat q3(imgFreqShifted, Rect(cx, cy, cx, cy)); Mat tmp; q0.copyTo(tmp); q3.copyTo(q0); tmp.copyTo(q3); q1.copyTo(tmp); q2.copyTo(q1); tmp.copyTo(q2); // Create a mask to filter out the sinusoidal noise Mat mask(img.size(), CV_32FC1, Scalar(0)); int radius = 20; Point center(img.cols / 2, img.rows / 2); circle(mask, center, radius, Scalar(1), -1); // Apply the mask to the frequency spectrum Mat imgFreqFiltered; multiply(imgFreqShifted, mask, imgFreqFiltered); // Perform inverse Fourier transform Mat imgFiltered; idft(imgFreqFiltered, imgFiltered, DFT_SCALE | DFT_REAL_OUTPUT); // Show the results namedWindow("Original", WINDOW_AUTOSIZE); imshow("Original", img); namedWindow("Noisy", WINDOW_AUTOSIZE); imshow("Noisy", imgFreqShifted); namedWindow("Filtered", WINDOW_AUTOSIZE); imshow("Filtered", imgFiltered); waitKey(0); return 0; } ``` 该代码首先将lena图像加载为灰度图像,然后添加正弦噪声。接下来,它执行傅里叶变换,并将零频率分量移动到频谱的心。然后,它创建一个掩膜,以过滤掉正弦噪声。通过将掩膜应用于频谱,可以得到过滤后的频谱。最后,它执行逆傅里叶变换以恢复图像,并显示原始图像、噪声图像和过滤后的图像。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值