Ask Your Question
4

Adding Noise to Image - Opencv

asked 2015-08-14 03:03:22 -0600

updated 2020-11-28 06:04:23 -0600

Hi everyone!

I'm trying to to add noise to an Image & then Denoise it to test my DeNoising algorithm! So for benchmark i'm referring this Online Test samples. I'm trying to replicate the Noise model.

With reference to this threads 1 , 2 I'm adding noise to image like this!

Mat mSource_Bgr;
mSource_Bgr= imread(FileName_S,1);

double m_NoiseStdDev=10;

Mat mNoise_Bgr = mSource_Bgr.clone();
Mat mGaussian_noise = Mat(mSource_Bgr.size(),CV_8UC3);

randn(mGaussian_noise,0,m_NoiseStdDev);
mNoise_Bgr += mGaussian_noise;

normalize(mNoise_Bgr,mNoise_Bgr,0, 255, CV_MINMAX, CV_8UC3);

imshow("Output Window",mNoise_Bgr);
//imshow("Gaussian Noise",mGaussian_noise);

My Input Image

enter image description here

Output Image with Noise

enter image description here

Problem:

Adding Noise to the image alters overall brightness of the Image which in turn alters my final results PSNR!

I want to get the results as much as closer to this one! enter image description here

What i have tried so far!

I have tried to add the noise only in the color channel.

  1. Convert the Input image into YUV Color space
  2. Add the Noise only in the UV Color Channels & Keep the Y channel unaltered.

    Results are very bad & the overall color of the image is getting altered! Will add the code if needed!

So any advice regarding this is much appreciated! May be give me some formulas for adding Noise to the image!

edit retag flag offensive close merge delete

Comments

2

Input and output images seem to have roughly same brightness to me. What ranges are you talking about? Anyway, I don't think it's possible to get exact brightness between the two images, because the noise is by definition unwanted strange pixels values, so they will definitely alter the image statistics. Moreover, gaussian noise is a random process, so you will never get same output twice, and therefore you will probably never get same brightness for all outputs

LorenaGdL gravatar imageLorenaGdL ( 2015-08-14 03:17:42 -0600 )edit

@LorenaGdL you are right by the way! But if you look at the samples provided in the benchmark images, you can see that the noise is getting added only in the color channel & the overall image brightness is not getting affected!

Balaji R gravatar imageBalaji R ( 2015-08-14 05:05:29 -0600 )edit

3 answers

Sort by ยป oldest newest most voted
4

answered 2015-08-14 05:54:09 -0600

updated 2016-06-07 06:18:04 -0600

I have found the possible bug in my code which is the Noise Mat type(Unsigned char). This will trim the Negative values from the Noise Mat, so that image will look brighter! Here is my updated code!

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <iostream>

using namespace cv;
using namespace std;

inline uchar Clamp(int n)
{
    n = n>255 ? 255 : n;
    return n<0 ? 0 : n;
}

bool AddGaussianNoise(const Mat mSrc, Mat &mDst,double Mean=0.0, double StdDev=10.0)
{
    if(mSrc.empty())
    {
        cout<<"[Error]! Input Image Empty!";
        return 0;
    }

    Mat mGaussian_noise = Mat(mSrc.size(),CV_16SC3);
    randn(mGaussian_noise,Scalar::all(Mean),Scalar::all(StdDev));

    for (int Rows = 0; Rows < mSrc.rows; Rows++)
    {
        for (int Cols = 0; Cols < mSrc.cols; Cols++)
        {
            Vec3b Source_Pixel= mSrc.at<Vec3b>(Rows,Cols);
            Vec3b &Des_Pixel= mDst.at<Vec3b>(Rows,Cols);
            Vec3s Noise_Pixel= mGaussian_noise.at<Vec3s>(Rows,Cols);

            for (int i = 0; i < 3; i++)
            {
                int Dest_Pixel= Source_Pixel.val[i] + Noise_Pixel.val[i];
                Des_Pixel.val[i]= Clamp(Dest_Pixel);
            }
        }
    }

    return true;
}

bool AddGaussianNoise_Opencv(const Mat mSrc, Mat &mDst,double Mean=0.0, double StdDev=10.0)
{
    if(mSrc.empty())
    {
        cout<<"[Error]! Input Image Empty!";
        return 0;
    }
    Mat mSrc_16SC;
    Mat mGaussian_noise = Mat(mSrc.size(),CV_16SC3);
    randn(mGaussian_noise,Scalar::all(Mean), Scalar::all(StdDev));

    mSrc.convertTo(mSrc_16SC,CV_16SC3);
    addWeighted(mSrc_16SC, 1.0, mGaussian_noise, 1.0, 0.0, mSrc_16SC);
    mSrc_16SC.convertTo(mDst,mSrc.type());

    return true;
}


int main(int argc, const char* argv[])
{
    Mat mSource= imread("input.png",1); 
    imshow("Source Image",mSource);

    Mat mColorNoise(mSource.size(),mSource.type());

    AddGaussianNoise(mSource,mColorNoise,0,10.0);

    imshow("Source + Color Noise",mColorNoise); 


    AddGaussianNoise_Opencv(mSource,mColorNoise,0,10.0);//I recommend to use this way!

    imshow("Source + Color Noise OpenCV",mColorNoise);  

    waitKey();
    return 0;
}
edit flag offensive delete link more

Comments

Thanks a lot for your prompt update

Hossain Md Shakhawat gravatar imageHossain Md Shakhawat ( 2016-06-07 04:34:43 -0600 )edit

I have added noise to color image in this way. But when I am calculating the MSE, it is very low compared to the added noise. For std=20, the MSE is below 200. But I think MSE should be close to square of std of the random noise(if std=20 then MSE around 400). How to add noise so that the MSE becomes square of the standard deviation of the noise?

Hossain Md Shakhawat gravatar imageHossain Md Shakhawat ( 2016-06-07 06:15:02 -0600 )edit

@Hossain Md Shakhawat BYTE is equalent to uchar

Balaji R gravatar imageBalaji R ( 2016-06-07 06:20:16 -0600 )edit

Another fact is I am adding same amount of noise to different color images. But when calculating MSE, their values are different for different images. Why is that? According to my understanding it should same for all images, if the amount of noise being added is same.

Hossain Md Shakhawat gravatar imageHossain Md Shakhawat ( 2016-06-17 08:37:26 -0600 )edit
3

answered 2015-08-20 08:39:42 -0600

theodore gravatar image

updated 2015-08-20 08:50:29 -0600

Indeed your issue was that you were not working with signed images. And in the following code you can find an alternative in order to avoid looping through the image pixels, which my guess would be that it is more time consuming (I have not test it to be honest) than using the internal functions of opencv:

void addGaussianNoise(Mat &image, double average=0.0, double standard_deviation=10.0)
{
    // We need to work with signed images (as noise can be
    // negative as well as positive). We use 16 bit signed
    // images as otherwise we would lose precision.
    Mat noise_image(image.size(), CV_16SC3);
    randn(noise_image, Scalar::all(average), Scalar::all(standard_deviation));
    Mat temp_image;
    image.convertTo(temp_image,CV_16SC3);
    addWeighted(temp_image, 1.0, noise_image, 1.0, 0.0, temp_image);
    temp_image.convertTo(image,image.type());
}
edit flag offensive delete link more

Comments

This solved my problem

Hossain Md Shakhawat gravatar imageHossain Md Shakhawat ( 2015-12-29 21:22:31 -0600 )edit
2

answered 2015-08-14 04:23:36 -0600

LBerger gravatar image

updated 2015-08-14 06:36:47 -0600

As you gaussian noise is ranging 0 to 255 you add energy to image I think you can substract mean to your result and it should be OK

Mat mSource_Bgr;
mSource_Bgr= imread("c:/Users/Laurent.PC-LAURENT-VISI/Downloads/ReaMu.png",CV_LOAD_IMAGE_ANYCOLOR);

double m_NoiseStdDev=10;

Mat mNoise_Bgr = mSource_Bgr.clone();
Mat mGaussian_noise = Mat(mSource_Bgr.size(),CV_8UC3);

randn(mGaussian_noise,0,m_NoiseStdDev);
double minIm,maxIm;

std::vector<Mat> plan;
split(mGaussian_noise,plan);
for (int i = 0; i < mGaussian_noise.channels(); i++)
{
minMaxIdx(plan[i],&minIm,&maxIm);
cout << minIm << "\t";
cout << maxIm << "\n";
}
mNoise_Bgr += mGaussian_noise;
Scalar x=mean(mGaussian_noise);
cout << x << "\n";
subtract(mNoise_Bgr,x,mNoise_Bgr);

imshow("Output Window",mNoise_Bgr);
waitKey();

Following remark from @LorenaGdL and @Balaji R I think this code is better (negative value at the end are not process and it could be a problem) :

Mat mSource_Bgr;
double minIm,maxIm;
std::vector<Mat> plan;
Scalar x;

mSource_Bgr= imread("ReaMu.png",CV_LOAD_IMAGE_ANYCOLOR);
cout << "Original image\n";
split(mSource_Bgr,plan);
for (int i = 0; i < mSource_Bgr.channels(); i++)
{
    minMaxIdx(plan[i],&minIm,&maxIm);
    cout << minIm << "\t";
    cout << maxIm << "\n";
}
x=mean(mSource_Bgr);
cout << x << "\n";


double m_NoiseStdDev=10;

Mat mNoise_Bgr ;
mSource_Bgr.convertTo( mNoise_Bgr,CV_32FC3, 1,0);


Mat mGaussian_noise = Mat(mSource_Bgr.size(),CV_32FC3);

randn(mGaussian_noise,0,m_NoiseStdDev);
mNoise_Bgr += mGaussian_noise;


cout << "Gaussian noise\n";
split(mGaussian_noise,plan);
for (int i = 0; i < mGaussian_noise.channels(); i++)
{
    minMaxIdx(plan[i],&minIm,&maxIm);
    cout << minIm << "\t";
    cout << maxIm << "\n";
}
x=mean(mGaussian_noise);
cout << x << "\n";

cout << "Result image+ gausssian noise\n";
split(mNoise_Bgr,plan);
for (int i = 0; i < mNoise_Bgr.channels(); i++)
{
    minMaxIdx(plan[i],&minIm,&maxIm);
    cout << minIm << "\t";
    cout << maxIm << "\n";
}
x=mean(mNoise_Bgr);
cout << x << "\n";

Mat result;
mNoise_Bgr.convertTo(result,CV_8UC3,1,0);
imshow("Output Window",result);
cout << "Image with noise\n";
split(result,plan);
for (int i = 0; i < mGaussian_noise.channels(); i++)
{
    minMaxIdx(plan[i],&minIm,&maxIm);
    cout << minIm << "\t";
    cout << maxIm << "\n";
}
x=mean(result);
cout << x << "\n";

waitKey();
edit flag offensive delete link more

Comments

I don't agree. That will alter those pixels that were not affected by the noise. That's not what happens in real scenarios, and a denoising algorithm shouldn't be based on that.

LorenaGdL gravatar imageLorenaGdL ( 2015-08-14 04:48:59 -0600 )edit

@LorenaGdL I think that question was about brightness. In code example given by @Balaji R gaussian noise was not zero mean. Adding this noise increases image brightness. After what do you mean by real scenarios ? So many noises exist in real world...

LBerger gravatar imageLBerger ( 2015-08-14 05:05:54 -0600 )edit

@Balaji R It depends which process is added (or multiplied or ...) to your signal.

For example you can an aquarium between your book and your camera. After in this aquarium you 've got small particles and a temperature gradient and a flow and some fishes....

IMHO There is no general algorithm for denoising (and simulate noise)

LBerger gravatar imageLBerger ( 2015-08-14 05:14:08 -0600 )edit

@LBerger: just saying that in my opinion a denoising algorithm shouldn't be based on a noise that generates an output image with the very same brightness as the input image. Want to use a zero mean noise? Perfect, but the mean will probably be slightly different from zero each time the noise is added, and the deviation shouldn't be important to the denoising algorithm. Subtracting the exact mean of each channel in the noise matrices seems too artificial to me. Does that noise exist in the world? Sure. Is a good way to generalize? I don't think so.

LorenaGdL gravatar imageLorenaGdL ( 2015-08-14 05:32:34 -0600 )edit

Moreover I don't like the code itself. The reason is you're using a random Gaussian noise of mean zero and standard deviation 10, but then you're storing it in a 8UC3 Mat, so you're just using the positive part of the probability function (negative values are discarded). Of course when you then subtract the means you end up with a zero mean noise (same brightness), but that's not gaussian noise and therefore the standard deviation loses its meaning.

LorenaGdL gravatar imageLorenaGdL ( 2015-08-14 05:53:29 -0600 )edit

@LorenaGdL Ok you are right I Change my code and you can give your opinion how to process negative value or greater than 255. It could be threshold or changed dynamic or ...

LBerger gravatar imageLBerger ( 2015-08-14 07:00:29 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2015-08-14 03:03:22 -0600

Seen: 24,745 times

Last updated: Jun 07 '16