#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
#define TWO_PI 6.2831853071795864769252866
#define N 1
Mat g_srcImage, g_dstImage1,g_dstImage2,out1,out2,out3;//存储图片的Mat类型
double psnr;
//求中值
void median(uchar p[][9],uchar *q)
{
uchar t;
for(int k=0;k<N;k++)
{
for(int i=0;i<8;i++)
{
for(int j=0;j<8-i;j++)
{
if(p[k][j]<p[k][j+1])
{
t=p[k][j];
p[k][i]=p[k][j+1];
p[k][j+1]=t;
}
}
}
*(q+k)=p[k][4];
}
}
//中值滤波
void filter(Mat &src,Mat &dst)
{
uchar p[N][9],q[N];
for(int i = 1 ; i < src.rows-1 ; i++)
{
for(int j = N ; j < src.cols-2*N+1 ; j+=N)
{
for(int k=0;k<N;k++)
{
p[k][0]=src.data[N*((i-1)*src.cols+j+k-N)];
p[k][1]=src.data[N*((i-1)*src.cols+j+k)];
p[k][2]=src.data[N*((i-1)*src.cols+j+k+N)];
p[k][3]=src.data[N*(i*src.cols+j+k-N)];
p[k][4]=src.data[N*(i*src.cols+j+k)];
p[k][5]=src.data[N*(i*src.cols+j+k+N)];
p[k][6]=src.data[N*((i+1)*src.cols+j+k-N)];
p[k][7]=src.data[N*((i+1)*src.cols+j+k)];
p[k][8]=src.data[N*((i+1)*src.cols+j+k+N)];
}
median(p,q);
for(int k=0;k<N;k++)
{
dst.data[N*((i-1)*src.cols+j+k-N)]=q[k];
dst.data[N*((i-1)*src.cols+j+k)]=q[k];
dst.data[N*((i-1)*src.cols+j+k+N)]=q[k];
dst.data[N*(i*src.cols+j+k-N)]=q[k];
dst.data[N*(i*src.cols+j+k)]=q[k];
dst.data[N*(i*src.cols+j+k+N)]=q[k];
dst.data[N*((i+1)*src.cols+j+k-N)]=q[k];
dst.data[N*((i+1)*src.cols+j+k)]=q[k];
dst.data[N*((i+1)*src.cols+j+k+N)]=q[k];
}
}
}
}
//给图像加椒盐噪声
static void salt(Mat image, int n)
{
int i,j;
for (int k=0; k<n; k++)
{
// rand()是随机数生成器
i= rand()%image.cols;
j= rand()%image.rows;
if (image.type() == CV_8UC1)
{ // 灰度图像
image.at<uchar>(j,i)= 255;
}
else if (image.type() == CV_8UC3)
{ // 彩色图像
image.at<cv::Vec3b>(j,i)[0]= 255;
image.at<cv::Vec3b>(j,i)[1]= 255;
image.at<cv::Vec3b>(j,i)[2]= 255;
}
}
}
//给图像加高斯噪声:高斯噪声出现在图像的每一个点上,而值的大小却是随机的。
//利用Box-Muller变换可以产生Gaussian噪声:首先产生服从均匀分布的随机数2个,然后再通过相关等式的变换
//产生服从高斯分布的数据。
//利用Box-Muller变换产生服从正态分布的随机数
double generateGaussianNoise()
{
static bool hasSpare = false;
static double rand1, rand2;
if (hasSpare)
{
hasSpare = false;
return sqrt(rand1) * sin(rand2);
}
hasSpare = true;
rand1 = rand() / ((double)RAND_MAX);
if (rand1 < 1e-100) rand1 = 1e-100;
rand1 = -2 * log(rand1);
rand2 = (rand() / ((double)RAND_MAX)) * TWO_PI;
return sqrt(rand1) * cos(rand2);
}
//
static void AddGaussianNoise(Mat& image)
{
CV_Assert(image.depth() != sizeof(uchar));
int channels = image.channels();
int nRows = image.rows;
int nCols = image.cols * channels;
if (image.isContinuous()){
nCols *= nRows;
nRows = 1;
}
int i, j;
uchar* p;
for (i = 0; i < nRows; ++i){
p = image.ptr<uchar>(i);
for (j = 0; j < nCols; ++j){
double val = p[j] + generateGaussianNoise() * 128;
if (val < 0)
val = 0;
if (val > 255)
val = 255;
p[j] = (uchar)val;
}
}
}
//高斯滤波:首先产生一个高斯滤波核,再采用滑动模板窗口的方法滤波处理图片。
//用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。
///产生二维的高斯内核 sigma 方差的大小 值越大图像越模糊, size模板的大小
static cv::Mat generate_gassian_kernel(double u, double sigma, cv::Size size)
{
int width = size.width;
int height = size.height;
cv::Mat gassian_kernel(cv::Size(width, height), CV_64FC1);
double sum = 0;
double sum_sum = 0;
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
{
sum = 1.0 / 2.0 / CV_PI / sigma / sigma * exp(-1.0 * ((i - width / 2)*(i - width / 2) + (j - width / 2)*(j - width / 2)) / 2.0 / sigma / sigma);
sum_sum += sum;
gassian_kernel.ptr<double>(i)[j] = sum;
}
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
{
gassian_kernel.ptr<double>(i)[j] /= sum_sum;
}
return gassian_kernel;
}
///高斯滤波
void lmt_gaussian_blur(cv::Mat& img_src, cv::Mat& img_dst, cv::Size kernel_size)
{
img_dst = cv::Mat(cv::Size(img_src.cols, img_src.rows), img_src.type());
int cols = img_src.cols;
int rows = img_src.rows;
int channels = img_src.channels();
cv::Mat gassian_kernel = generate_gassian_kernel(0,0.8, kernel_size);
int width = kernel_size.width / 2;
int height = kernel_size.height / 2;
for (int i = height; i < rows - height; i++)
{
for (int j = width; j < cols - width; j++)
{
for (int k = 0; k < channels; k++)
{
double sum = 0.0;
for (int m = -height; m <= height; m++)
{
for (int n = -width; n <= width; n++)
{
sum += (double)(img_src.ptr<uchar>(i + m)[(j + n)*channels + k]) * gassian_kernel.ptr<double>(height + m)[width + n];
}
}
if (sum > 255.0)
sum = 255;
if (sum < 0.0)
sum = 0;
img_dst.ptr<uchar>(i)[j*channels + k] = (uchar)sum;
}
}
}
}
//计算滤波前后图像的PSNR,得到的差值越小,就代表两者的图像差别越大。普遍基准为30dB
double getPSNR(const Mat& I1, const Mat& I2)
{
Mat s1;
absdiff(I1, I2, s1); // |I1 - I2|AbsDiff函数是 OpenCV 中计算两个数组差的绝对值的函数
s1.convertTo(s1, CV_32F); // 这里使用的CV_32F来计算,因为8位无符号char是不能进行平方计算
s1 = s1.mul(s1); // |I1 - I2|^2
Scalar s = sum(s1); //对每一个通道进行加和
double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
if( sse <= 1e-10) // 对于非常小的值我们将约等于0
return 0;
else
{
double mse =sse /(double)(I1.channels() * I1.total()); //计算MSE:均方误差
double psnr = 10.0*log10((255*255)/mse); //计算峰值信噪比的公式
return psnr;//返回PSNR
}
}
int main()
{
vector<Mat> channel1,channel2;
// 载入原图
g_srcImage = imread("1.jpg", 1);
if (!g_srcImage.data) { printf("Oh,no,读取srcImage错误~! \n"); return false; }
//克隆原图到三个Mat类型中
g_dstImage1 = g_srcImage.clone();
g_dstImage2 = g_srcImage.clone();
//显示原图
namedWindow("【<0>原图窗口】", 1);
imshow("【<0>原图窗口】", g_srcImage);
//得到椒盐噪声并存储为.jpg
namedWindow("【<1>加椒盐噪声】", 1);
salt(g_dstImage1, 50000);
imshow("【<1>加椒盐噪声】", g_dstImage1);
//得到高斯噪声并存储为.jpg
namedWindow("【<2>加高斯噪声】", 1);
AddGaussianNoise(g_dstImage2);
imshow("【<2>加高斯噪声】",g_dstImage2);
imwrite("加椒盐噪声.jpg", g_dstImage1);
imwrite("加高斯噪声.jpg",g_dstImage2);
//try {
// imwrite("加椒盐噪声.png",g_srcImage);
//}
//catch (runtime_error& ex) {
// fprintf(stderr, "Exception converting image to PNG format: %s\n", ex.what());
// return 1;
//}
//彩色图像的话就分离色彩通道进行处理
Mat dstImg1(g_dstImage1.size(), CV_8UC1, Scalar(0));
Mat dstImg2(g_dstImage1.size(), CV_8UC1, Scalar(0));
Mat dstImg3(g_dstImage1.size(), CV_8UC1, Scalar(0));
Mat dstImg(g_dstImage1.size(), CV_8UC3, Scalar(0,0,0));
split(g_dstImage1,channel1);//分离色彩通道
split(g_dstImage1,channel2);//分离色彩通道
filter(channel1[0],dstImg1);
filter(channel1[1],dstImg2);
filter(channel1[2],dstImg3);
//imshow("destination1", dstImg1);
//imshow("destination2", dstImg2);
//imshow("destination3", dstImg3);
channel2[0]=dstImg1;
channel2[1]=dstImg2;
channel2[2]=dstImg3;
merge(channel2,dstImg);
imshow("添加椒盐噪声的图像经中值滤波后", dstImg);//显示目标图
imwrite("椒盐噪声经中值滤波后.jpg",dstImg);
lmt_gaussian_blur(g_dstIm
评论0
最新资源