/*入门学习 图像滤波
Filtering 是图像处理中的一个基本操作,其目的是为了提取图像中被认为重要的那些部分。
滤波可以去除图像中的噪声,提取感兴趣的视觉特征,允许图像重采样等。
这里我们了解一些基本的内容。
观察一幅图像时,我们看到不同的灰度(或彩色值)在图像中的分布。图像之间存在不同是因为他们有不同的灰度分布。
因此存在另一种进行图像处理的方式:观察图像中存在的灰度的变化。
一些图像中包含大面积恒定的灰度强度,另一些图片中灰度变化迅速。
因此观察图像中灰度或者像素点变化的频率构成了一种描述图像的方式,这种观点被称为频域。通过观察灰度的分布
来描述一幅图像 被称为空间区域。
空间域又称图像空间(image space)。由图像像元组成的空间。
在图像空间中以长度(距离)为自变量直接对像元值进行处理称为空间域处理。
以空间坐标作为变量进行的研究就是空间域。
频域分析按照高频到低频的次序 ,分解图像到频率内容。低频对应区域的图像强度变化缓慢,高频区域是由快速变化的图像
强度生成的。图像时二维的,他包含垂直频率(垂直方向的变化)和水平频率(水平方向的变化)
频域分析的框架下,滤波操作的作用是增强部分频段,同时限制或者衰减其他频段。
低频滤波器去除了图像中的高频成分,高通滤波器去除了低频成分。
这篇博客个人觉得讲的非常好:https://blog.csdn.net/qq_36359022/article/details/80154900
*/
/*下面开始学习 低通滤波器 */
#include<opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
double **getGuassionArray(int size, double sigma)
{
/*这句话暂时我还讲述不太明白 反正是定义了一个二维数组
double *Arr = new double[size] 创建一个动态数组 Arr指向这个数组的地址
double ** Arr = new double*[size]; 中 double *[]应该是定义了一个指针数组
这样这句话 应该就是定义了一个指向指针数组的指针 大概这样理解吧
比如说 double *[size]里面的指针指向了四个一维数组 每一个一维数组里面有四个元素
这时候(void*)(*Arr)+1 得到地址 应该是第二个一维数组的地址
这里加1 指针哪里应该是加的四个元素的类型的字节 我没试过 应该是这样吧
*/
double sum = 0;
int i, j;
int center = (size-1) / 2;
double ** Arr = new double*[size];
for (i = 0; i < size; i++)
{
Arr[i] = new double[size]; //Arr[i]其实就是指针 Arr+i就是指向Arr[i]的指针 Arr[i]指向一个一维数组
}
for (i = 0; i < size; i++)
{
for (j = 0; j < size; j++)
{
Arr[i][j] = exp(-((i - center)*(i - center) + (j - center)*(j - center)) / (2 * sigma*sigma));
sum += Arr[i][j];
}
}
for (i = 0; i < size; i++)
{
for (j = 0; j < size; j++)
{
Arr[i][j] /= sum;
}
}
return Arr;
}
/*此 函数是用来 输出得到的矩阵 或者说叫核或者掩码
可以看到sigma取不同的值时 得到掩码的值是不同的 sigma的取值越小
核中间的像素权值就越大 这也和概率中高斯函数的性质是一样的 sigma的取值越小 图像越高窄
*/
void printfKernel()
{
double **Arr;
Arr = getGuassionArray(3, 10);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
cout << Arr[i][j] << '\t';
}
cout << endl;
}
}
/* 高斯处理 */
/*const Mat image 前面加一个const 有什么用呢 image前面没有&符号啊 是不让对这个图像操作吗
为啥 image.at<Vec3b>(i, j)[0] = 0;操作不合法呢??
*/
void myGaussian(const Mat image, Mat & result)
{
double **Arr;
Arr = getGuassionArray(3, 1.5);
int nl = image.rows;
int nc = image.cols;
Mat temp(image.size(), image.type());
for (int i = 0; i < nl; i++)
{
for (int j = 0; j < nc; j++)
{
if ((i > 0) && (i < nl - 1) && (j > 0) && (j < nc - 1))
{
temp.at<Vec3b>(i, j)[0] = 0;
temp.at<Vec3b>(i, j)[1] = 0;
temp.at<Vec3b>(i, j)[2] = 0;
for (int x = 0; x < 3; x++)
{
for (int y = 0; y < 3; y++)
{
temp.at<Vec3b>(i, j)[0] += Arr[x][y] * image.at<Vec3b>(i + 1 - x, j + 1 - y)[0] ;
temp.at<Vec3b>(i, j)[1] += Arr[x][y] * image.at<Vec3b>(i + 1 - x, j + 1 - y)[1] ;
temp.at<Vec3b>(i, j)[2] += Arr[x][y] * image.at<Vec3b>(i + 1 - x, j + 1 - y)[2] ;
}
}
}
}
}
temp.copyTo(result);
}
void namesSet()
{
namedWindow("原始图像", 0);
cvResizeWindow("原始图像", 433, 600);
namedWindow("椒盐图像", 0);
cvResizeWindow("椒盐图像", 433, 600);
namedWindow("自定义高斯", 0);
cvResizeWindow("自定义高斯", 433, 600);
namedWindow("OpenCv高斯", 0);
cvResizeWindow("OpenCv高斯", 433, 600);
}
void salt(Mat image, Mat &result,int k)
{
image.copyTo(result);
for (; k > 0; k--)
{
int i = rand() % result.rows;
int j = rand() % result.cols;
if (result.channels() == 1)
{
result.at<uchar>(i, j) = 255;
}
if (result.channels() == 3)
{
result.at<Vec3b>(i, j) = 255;
result.at<Vec3b>(i, j) = 255;
result.at<Vec3b>(i, j) = 255;
}
}
}
int main()
{
Mat image, result1,result2,result3;
image = imread("Test1.jpg", IMREAD_UNCHANGED);
namesSet();
salt(image, result1,3000);
GaussianBlur(result1, result2, Size(3,3), 1.5);
myGaussian(result1, result3);
imshow("原始图像",image);
imshow("椒盐图像", result1);
imshow("OpenCv高斯", result2);
imshow("自定义高斯", result3);
printfKernel();
waitKey(0);
return 0;
}
来源:https://blog.csdn.net/HopesunIce/article/details/100165984