C++手敲灰度图均值滤波中值滤波高斯滤波
一、均值滤波(Meaning Filtering)概念
均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标像素为中心的周围8个像素,构成一个滤波模板,即包括目标像素本身),再用模板中的全体像素的平均值来代替原来像素值。
代码实现:
①先引入头文件,声明核的大小为3*3
#include<opencv2/opencv.hpp>#define filter_size 3using namespace cv;
②导入原始图片,生成高斯噪声。显示原始图片、生成的噪声图片以及噪声噪声和原图片的叠加
注意噪声图片的大小和原始图片保持一致。其中原图加噪声的窗口我设置为可以随机改变大小,方便后面结果对比。
Mat image = imread("C:\\Users\\Czhannb\\Desktop\\CV.png", IMREAD_GRAYSCALE);
Mat noise = Mat::zeros(Size(image.cols, image.rows), image.type());
imshow("原图", image);//加入Gau斯噪声
RNG rng;
rng.fill(noise, RNG::NORMAL, 10, 30);
imshow("噪声", noise);//拼起来
image = image + noise;
namedWindow("原图加噪声", WINDOW_FREERATIO);
imshow("原图加噪声", image);
原图: 噪声:
合起来:
③得到待处理图片之后,依据均值滤波原理处理图片。
首先创建一张空白图片,其维度和原始图片一致。
Mat module_mean = Mat::zeros(Size(image.cols, image.rows), image.type());
由于核的大小为3*3,也就是说核只能够向右移动image.cols-3次,向下移动image.rows-3次。
对于每一次遍历,九个像素点的均值将替代核中心的像素。这样的话,如果不对图片进行处理(Padding等等),图片最外面一层的像素值是不会改变的。不过对于我们由几百行几百列像素点组成的图片而言,这点可以忽略掉。
我们先用两个for循环,遍历到每一个像素点(其中最右边的两列以及最下面的两行不能到达)。
遍历到能够到达的像素点之后,求九个像素点的均值,然后赋给中间的像素。代码如下:
for (int i = 0; i < image.rows - 2; i++) {for (int j = 0; j < image.cols - 2; j++) {int sum = 0; for (int row = 0; row < filter_size; row++) {for (int col = 0; col < filter_size; col++) {sum += image.at<uchar>(row + i, col + j); //求每一个3x3小矩阵的像素之和}}module_mean.at<uchar>(i + 1, j + 1) = sum / 9; //把均值赋予空白图片对应的像素}}
图中最后一行代码:把像素点均值赋予给了中心像素的位置表示是(i + 1, j + 1)。这是一个相对坐标,当i=j=0时,也就是第一轮遍历,像素的中心出现在(1,1)。后面也是这样处理。
里面的两个for循环作用是计算每一次遍历中3*3像素点之和。
这样一来就大功告成了!让我们来看看均值滤波之和的效果。
④结果对比
imshow("均值滤波之后", module_mean);
可见效果还行吧。。(均值滤波本来就有模糊的作用,加之截图又给了一层buff,大伙将就!)
讲完均值滤波来讲讲中值滤波。
二、中值滤波
中值滤波法是一种非线性平滑技术,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值.
中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,中值滤波的基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近真实值,从而消除孤立的噪声点。方法是用某种结构的二维滑动模板,将板内像素按照像素值的大小进行排序,生成单调上升(或下降)的为二维数据序列。二维中值滤波输出为g(x,y)=med{f(x-k,y-l),(k,l∈W)} ,其中,f(x,y),g(x,y)分别为原始图像和处理后图像。W为二维模板,通常为3*3,5*5区域,也可以是不同的形状,如线状,圆形,十字形,圆环形等。
代码实现:
①和均值滤波类似,我们先生成一张空白图片(全黑,形状和原始图像大小一致)
Mat module_mid = Mat::zeros(Size(image.cols, image.rows), image.type());
②相似的,我们亦需用两个for循环遍历能到达的像素。然后,与均值滤波不同的是,我们要做的不是把后面两个for循环遍历得到的像素值相加做平均,而是把它们放到一个vector容器中。这样做的原因是vector自带排序函数,这样就可以偷懒不用再给数组排序了。而我们想要的中值像素,就出现在vector[4]当中。
for (int i = 0; i < image.rows - 2; i++) {for (int j = 0; j < image.cols - 2; j++) {vector<int>vec; // 创建容器来装每一轮的九个像素值for (int row = 0; row < filter_size; row++) {for (int col = 0; col < filter_size; col++) {vec.push_back(image.at<uchar>(row + i, col + j)); // 每一个像素追加到容器后面}}sort(vec.begin(), vec.end()); // 排序(升序降序都可以)module_mid.at<uchar>(i + 1, j + 1) = vec[4]; //第五个元素就是中间值}}
每一轮遍历拿到中值像素vec[4]之后,赋给module_mid空白图片对应的像素点,即可大功告成。
③结果对比
imshow("中值滤波之后", module_mid);
可见效果也挺不错。。
三、高斯滤波
高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。 [1] 通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。
3*3的高斯核如下:
代码实现:
①先创建一个二维数组充当高斯核(越靠近中心像素,权重越大),后面再通过索引得到高斯核的值与原图像的像素点进行相乘。得到的结果做平均就可以赋给中心像素了。
int Gau_filter[3][3];for (int i = 0; i < filter_size; i++) {for (int j = 0; j < filter_size; j++) {if ((i==1)&&(j==1)) {Gau_filter[i][j] = 8;}else if ((i+j==filter_size-2)||(i+j==filter_size)) {Gau_filter[i][j] = 2;}else {Gau_filter[i][j] = 1;}}}
②与上述两个滤波方法一致,这里先生成一张空白图像。
Mat module_Gau = Mat::zeros(Size(image.cols, image.rows), image.type());
再通过两个for循环遍历,创建一个整型变量sum来记录下来每一轮加权求和的结果。
在嵌套的两个for循环中注意:对原图的遍历记为(row+i, col+j),而对高斯核的遍历记为[row][col]。
这样可以用相同的高斯核对每一次遍历的九个像素点做处理。
for (int i = 0; i < image.rows - 2; i++) {for (int j = 0; j < image.cols - 2; j++) {int sum = 0;for (int row = 0; row < filter_size; row++) {for (int col = 0; col < filter_size; col++) {sum +=image.at<uchar>(row+i, col+j)*Gau_filter[row][col];}}module_Gau.at<uchar>(i + 1, j + 1) = sum / 20;}}
20是高斯核的值求和。
③结果对比
imshow("高斯滤波之后", module_Gau);
效果也还行吧。
四、3*3核均值滤波中值滤波高斯滤波代码汇总
#include<opencv2/opencv.hpp>
#include<iostream>
#include<vector>using namespace cv;
using namespace std;#define filter_size 3
#define Filter_Size 5int main() {// 3*3模板Mat image = imread("C:\\Users\\Czhannb\\Desktop\\gray.png", IMREAD_GRAYSCALE);Mat noise = Mat::zeros(Size(image.cols, image.rows), image.type());imshow("原图", image);imshow("零噪声", noise);//加入Gau斯噪声RNG rng;rng.fill(noise, RNG::NORMAL, 10, 30);imshow("噪声", noise);//拼起来image = image + noise;namedWindow("原图加噪声", WINDOW_FREERATIO);imshow("原图加噪声", image);// 定义高斯核int Gau_filter[3][3];for (int i = 0; i < filter_size; i++) {for (int j = 0; j < filter_size; j++) {if ((i==1)&&(j==1)) {Gau_filter[i][j] = 8;}else if ((i+j==filter_size-2)||(i+j==filter_size)) {Gau_filter[i][j] = 2;}else {Gau_filter[i][j] = 1;}}}// 均值滤波 - 图像边缘不做处理,即无padding// 前两个for循环遍历整张图Mat module_mean = Mat::zeros(Size(image.cols, image.rows), image.type());for (int i = 0; i < image.rows - 2; i++) {for (int j = 0; j < image.cols - 2; j++) {int sum = 0; for (int row = 0; row < filter_size; row++) {for (int col = 0; col < filter_size; col++) {sum += image.at<uchar>(row + i, col + j); //求每一个3x3小矩阵的像素之和}}module_mean.at<uchar>(i + 1, j + 1) = sum / 9; //把均值赋予新的像素矩阵}}imshow("均值滤波之后", module_mean);//中值滤波 - 图像边缘不做处理// 前两个for循环遍历整张图Mat module_mid = Mat::zeros(Size(image.cols, image.rows), image.type());for (int i = 0; i < image.rows - 2; i++) {for (int j = 0; j < image.cols - 2; j++) {vector<int>vec; // 创建容器来装每一轮的九个像素值for (int row = 0; row < filter_size; row++) {for (int col = 0; col < filter_size; col++) {vec.push_back(image.at<uchar>(row + i, col + j)); // 每一个像素追加到容器后面}}sort(vec.begin(), vec.end()); // 排序(升序降序都可以)module_mid.at<uchar>(i + 1, j + 1) = vec[4]; //第五个元素就是中间值}}imshow("中值滤波之后", module_mid);*///高斯滤波 - 图像边缘不做处理// 前两个for循环遍历整张图Mat module_Gau = Mat::zeros(Size(image.cols, image.rows), image.type());for (int i = 0; i < image.rows - 2; i++) {for (int j = 0; j < image.cols - 2; j++) {int sum = 0;for (int row = 0; row < filter_size; row++) {for (int col = 0; col < filter_size; col++) {sum +=image.at<uchar>(row+i, col+j)*Gau_filter[row][col];}}module_Gau.at<uchar>(i + 1, j + 1) = sum / 20;}}imshow("高斯滤波之后", module_Gau);waitKey(0);destroyAllWindows();return 0;
}
五、拓展
①既然有3*3,那么就会有5*5,6*6等等等等,但不是核越大越好,常言道做什么都有个界限。我还多准备了一份5*5核的均值滤波中值滤波核高斯滤波代码如下。要注意的当然就是边界问题、核以及图片的遍历问题、高斯核的大小更换等等问题。不过相信只要懂得了其中的原理,那么无论是几成几,做的过程大概的思路都是一样滴~
#include<opencv2/opencv.hpp>
#include<iostream>
#include<vector>using namespace cv;
using namespace std;#define filter_size 3
#define Filter_Size 5int main() {// 5*5模板Mat image = imread("C:\\Users\\Czhannb\\Desktop\\gray.png", IMREAD_GRAYSCALE);Mat noise = Mat::zeros(Size(image.cols, image.rows), image.type());imshow("原图", image);imshow("零噪声", noise);RNG rng;rng.fill(noise, RNG::NORMAL, 10, 30);imshow("噪声", noise);image = image + noise;namedWindow("原图加噪声", WINDOW_FREERATIO);imshow("原图加噪声", image);// 定义高斯核int Gau_filter[5][5] = { 1,1,2,1,1,1,2,4,2,1,2,4,8,4,2,1,2,4,2,1,1,1,2,1,1};// 均值滤波 - 图像边缘不做处理,即无padding// 前两个for循环遍历整张图Mat module_mean = Mat::zeros(Size(image.cols, image.rows), image.type());for (int i = 0; i < image.rows - 4; i++) {for (int j = 0; j < image.cols - 4; j++) {int sum = 0;for (int row = 0; row < Filter_Size; row++) {for (int col = 0; col < Filter_Size; col++) {sum += image.at<uchar>(row + i, col + j); //求每一个5*5小矩阵的像素之和}}//cout << sum1 << " "<<sum2 <<" "<< sum3;module_mean.at<uchar>(i + 1, j + 1) = sum / 25; //把均值赋予新的像素矩阵}}imshow("均值滤波之后", module_mean);//中值滤波 - 图像边缘不做处理// 前两个for循环遍历整张图Mat module_mid = Mat::zeros(Size(image.cols, image.rows), image.type());for (int i = 0; i < image.rows - 4; i++) {for (int j = 0; j < image.cols - 4; j++) {vector<int>vec; // 创建容器来装每一轮的九个像素值for (int row = 0; row < Filter_Size; row++) {for (int col = 0; col < Filter_Size; col++) {vec.push_back(image.at<uchar>(row + i, col + j)); // 每一个像素追加到容器后面}}sort(vec.begin(), vec.end()); // 排序(升序降序都可以)module_mid.at<uchar>(i + 1, j + 1) = vec[12]; //第五个元素就是中间值}}imshow("中值滤波之后", module_mid);//高斯滤波 - 图像边缘不做处理// 前两个for循环遍历整张图Mat module_Gau = Mat::zeros(Size(image.cols, image.rows), image.type());for (int i = 0; i < image.rows - 4; i++) {for (int j = 0; j < image.cols - 4; j++) {int sum = 0;for (int row = 0; row < Filter_Size; row++) {for (int col = 0; col < Filter_Size; col++) {sum += image.at<uchar>(row + i, col + j) * Gau_filter[row][col];}}module_Gau.at<uchar>(i + 1, j + 1) = sum / 52;}}imshow("高斯滤波之后", module_Gau);waitKey(0);destroyAllWindows();return 0;
}
②如下给出了5*5核完成的均值滤波中值滤波以及高斯滤波,效果可以说比3*3好了不是一点点。(仅从去噪角度而言)
补充:
-2的原因是用了3*3的模板,模板从左上角开始向右移以及向下移,都是只能够移动image.rows-3次(比如说图像只有四列的话,3*3的模板只能移4-3=1次)这样一来的话最右边两列和最下面两行是遍历不到的。每一次移动都会锁定3*3个像素,也就是接下来两个for循环的操作(针对每次遍历到的9个像素),进行累加求平均或者排序完之后得到一个值赋给3*3模板的中间位置(这个位置的表示是i+1,j+1)(比如说第一次遍历的得到的结果应该放在0+1,0+1也就是1,1处)。创建一张空白图片的原因是拿来存放上面的运算结果,如果直接在原图上面更改的话会越算越错。遍历完了之后,空白图片的最外面的边没作处理,像素值还是原来的0。
C++手敲灰度图均值滤波中值滤波高斯滤波相关推荐
- 图像处理:推导五种滤波算法(均值、中值、高斯、双边、引导)
目录 概论 算法原理 1.均值滤波 2.中值滤波 3.高斯滤波 4.双边滤波 5.引导滤波 手写代码 Opencv代码实现 最后的总结 参考文章 概论 本来打算是分开推导的,但我觉得还是整个合集吧,避 ...
- 图像滤波算法整理--均值、中值、高斯、拉普拉斯算子、梯度算子:
首先分为平滑空间滤波器和锐化空间滤波器来进行介绍.平滑空间滤波器主要用于模糊处理和降低噪声,主要两类:均值滤波器和中值滤波器.锐化空间滤波器主要是:拉普拉斯算子和梯度算子. 一.均值滤波方法:对高斯噪 ...
- OpenCV函数简记_第三章数字图像的滤波处理(方框,均值,高斯,中值和双边滤波)
系列文章目录 OpenCV函数简记_第一章数字图像的基本概念(邻域,连通,色彩空间) OpenCV函数简记_第二章数字图像的基本操作(图像读写,图像像素获取,图像ROI获取,图像混合,图形绘制) Op ...
- 点云去噪(中值、高斯、均值、SOR滤波),及matlab的代码撰写-2021-7-21-
1 为什么点云会有噪声? 受到仪器.周围环境.被扫描目标本身的特性影响,点云数据中无法避免存在一些噪声.噪声的来源有很多,比如超过扫描设定范围的点:由于受到周围的风.周围物体的震动等影响产生的点:或者 ...
- 均值滤波 中值滤波 高斯平滑滤波
均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(以目标象素为中心的周围8个像素,构成一个滤波模板,即去掉目标像素本身),再用模板中的全体像素的平均值来代 ...
- opencv 滤波 方框滤波 均值滤波 高斯滤波 中值滤波 双边滤波
文章目录 一. 线性滤波 1.1. 方框滤波 demo 1.2. 均值滤波 demo 1.3. 高斯滤波 demo 二. 非线性滤波 2.1. 中值滤波 demo 2.2. 双边滤波 demo 结构体 ...
- 【opencv】(3) 图像滤波:均值、方框、中值、高斯
内容有: 均值滤波 cv2.blur(),方框滤波 cv2.boxFilter(),高斯滤波 cv2.GaussianBlur(),中值滤波 cv2.medianBlur() 滤波可理解为,平均卷积操 ...
- Opencv学习笔记 各向异性滤波/均值滤波/高斯滤波/中值滤波/加权中值滤波/高斯低通滤波
各向异性滤波 各向异性扩散滤波主要是用来平滑图像的,克服了高斯模糊的缺陷,各向异性扩散在平滑图像时是保留图像边缘的,和双边滤波很像. public static void ImageA ...
- 均值滤波高斯滤波中值滤波
1.均值滤波 均值滤波是一种线性滤波器,处理思路也很简单,就是将一个窗口区域中的像素计算平均值,然后将窗口中计算得到的均值设置为锚点上的像素值. 该算法有优点在于效率高,思路简单.同样,缺点也很明显, ...
最新文章
- 关于分页的解决方案收集
- boost::timer::auto_cpu_timer相关的测试程序
- R语言观察日志(part23)--bibliometrix包
- ubuntu MySQL安装指南
- Deep Learning 【Nature review】
- 用Python玩连连看是什么效果?
- cf1107e uva10559区间dp升维
- Vue+Webpack使用规范
- VS2010 常用快捷键
- Python数据可视化,Pyecharts库,国家卫健委疫情风险等级数据可视化
- iOS 打开第三方应用
- axure产品原型设计工具
- 神经网络、结构、权重和矩阵
- 忘记本地mysql密码_本地MySQL密码忘了,怎么找回?
- java同名变量在list中添加两次_去除集合中自定义对象的重复值(对象的成员变量值都相同)...
- 1. 什么是ThingsBoard
- c语言实验程序,C语言实验程序
- 扫雷,潜伏者(python)
- 纯JS Video标签的 视频播放、暂停、结束、长度 事件 Event 信息
- matlab卡西欧,史上最全计算器+数学计算工具(工程必备)