- 读入一幅摄像头图像,记为I
- 向图像加入高斯噪声,噪声的灰度要和图像的灰度在一个相当的水平上,记为J
- 计算图像I和J的均方误差
- 计算图像J的信噪比
本文是采用Box-Muller算法实现高斯分布的,而要借助Box-Muller算法产生高斯分布必须要有现成的均与分布随机数。
由rand()函数可以产生介于0 至 RAND_MAX 的随机数。因此,若要得到[0,1]的随机数,则可使用
rand() * (1.0 / RAND_MAX)
Box-Muller算法正是利用均匀分布产生高斯分布随机数,算法如下:
上式中的U1和U2就是两个均匀分布随机数,经过这样的一种计算之后就能产生一个Z服从均匀分布的随机数,这看起来太神奇了,不得不佩服这个算法。
说明一下,上面的三个式子,前两个取任何一个都可以用作算法,取正弦还是余弦是无所谓的。
另外一点,上面的式子仅仅只能产生标准的\(Z\sim N(0,1)\)高斯分布,若要产生给定的均值和方差其实也很简单。\[Y=\mu +\sigma Z\]
上式中的\(\mu \),\(\sigma \)就是可以自己手动定义的期望和标准差(方差开根号)。
//生成高斯噪声
double generateGaussianNoise(double mu, double sigma)
{
//定义小值
static double z0;
double u1, u2;
//构造随机变量
u1 = rand() * (1.0 / RAND_MAX); //生成[0,1]之间的随机数
u2 = rand() * (1.0 / RAND_MAX); //生成[0,1]之间的随机数
//构造高斯随机变量(Box-Muller算法)
z0 = sqrt(-2.0*log(u1))*cos(2 * CV_PI*u2);
return z0*sigma + mu;
}
//得到均方误差MSE
double getMSE(Mat & srcImage,Mat & dstImage)
{
Mat src = dstImage;
Mat dst = srcImage;
int channels = dstImage.channels();
int rowsNumber = src.rows;
int colsNumber = src.cols*channels;
double sigma=0.0;
double mse=0.0;
for (int i = 0; i < rowsNumber; i++)
{
for (int j = 0; j < colsNumber; j++)
{
mse += (src.ptr(i)[j] - dst.ptr(i)[j])*(src.ptr(i)[j] - dst.ptr(i)[j]);
}
}
mse=mse/(rowsNumber*colsNumber);
return mse;
}
其中,\(f(x,y)\)为原始图像(此处对应加噪声后的图像),\(g(x,y)\)为去噪后的图像(此处对应加噪声前的图像)。
//得到图片信噪比SNR
double getSNR(Mat & srcImage,Mat & dstImage)
{
Mat src = dstImage;
Mat dst = srcImage;
int channels = dstImage.channels();
int rowsNumber = src.rows;
int colsNumber = src.cols*channels;
double sigma=0.0;
double mse=0.0;
double SNR=0.0;
for (int i = 0; i < rowsNumber; i++)
{
for (int j = 0; j < colsNumber; j++)
{
sigma += (src.ptr(i)[j])*(src.ptr(i)[j]);
mse += (src.ptr(i)[j] - dst.ptr(i)[j])*(src.ptr(i)[j] - dst.ptr(i)[j]);
}
}
SNR=10*log10(sigma/mse);
return SNR;
}
#include
#include
using namespace cv;
using namespace std;
Mat myResize(Mat &srcImag, double width_ratio, double height_ratio);
double generateGaussianNoise(double m, double sigma);
Mat addGaussianNoise(Mat &srcImag);
double getSNR(Mat & srcImage,Mat & dstImage);
double getMSE(Mat & srcImage,Mat & dstImage);
int main()
{
//调用手机IP摄像头,此处改为0则调用电脑摄像头
VideoCapture video("http://admin:[email protected]:xxxx");
//读取一帧图片;前几帧成像效果差,故取第10帧的图片
Mat srcImage;
for (int i=1; i<10; i++)
{
video >> srcImage;
}
//Mat srcImage = imread("../orange.jpg");
//断开连接,否则手机端无法正常退出
video.release();
//缩放图像
srcImage=myResize(srcImage,0.2,0.2);
//判断图片读取是否成功
if (!srcImage.data)
{
cout << "读入图片错误!" << endl;
return -1;
}
Mat dstImage = addGaussianNoise(srcImage);
double SNR = getSNR(srcImage, dstImage);
double MSE = getMSE(srcImage, dstImage);
imshow("原图像", srcImage);
imshow("添加高斯噪声后的图像", dstImage);
cout<<"MSE: "<(i)[j] + generateGaussianNoise(0, 1)*255;
if (val < 0)
val = 0;
if (val > 255)
val = 255;
dstImage.ptr(i)[j] = (uchar)val;
}
}
return dstImage;
}
//得到图片信噪比SNR
double getSNR(Mat & srcImage,Mat & dstImage)
{
Mat src = dstImage;
Mat dst = srcImage;
int channels = dstImage.channels();
int rowsNumber = src.rows;
int colsNumber = src.cols*channels;
double sigma=0.0;
double mse=0.0;
double SNR=0.0;
for (int i = 0; i < rowsNumber; i++)
{
for (int j = 0; j < colsNumber; j++)
{
sigma += (src.ptr(i)[j])*(src.ptr(i)[j]);
mse += (src.ptr(i)[j] - dst.ptr(i)[j])*(src.ptr(i)[j] - dst.ptr(i)[j]);
}
}
SNR=10*log10(sigma/mse);
return SNR;
}
//得到均方误差MSE
double getMSE(Mat & srcImage,Mat & dstImage)
{
Mat src = dstImage;
Mat dst = srcImage;
int channels = dstImage.channels();
int rowsNumber = src.rows;
int colsNumber = src.cols*channels;
double sigma=0.0;
double mse=0.0;
for (int i = 0; i < rowsNumber; i++)
{
for (int j = 0; j < colsNumber; j++)
{
mse += (src.ptr(i)[j] - dst.ptr(i)[j])*(src.ptr(i)[j] - dst.ptr(i)[j]);
}
}
mse=mse/(rowsNumber*colsNumber);
return mse;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(test1)
set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "-std=c++11")
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(test1 test1.cpp)
target_link_libraries(test1 ${OpenCV_LIBS})
(人脸必须厚码哈哈哈哈)