本文共 6682 字,大约阅读时间需要 22 分钟。
① 不管是低通线性滤波还是高通线性滤波原理都是一样的,用图一所示的滤波器模板进行加权处理,将最终得到的R值赋给w5对应的像素。
②低通线性滤波和高通线性滤波不同之处就在于:③高频补偿滤波
原图像减去模糊处理后的图像,再将相减得到的模板乘以一个权重加给原图像。公式表式如下:①中值滤波
②最大值滤波
③最小值滤波
④一阶导数滤波
在图像进行锐化处理的过程中,有可能会出现图像灰度值大于255或者小于0的情况,所以遇到这种情况我们需要将图像的灰度值通过一些处理控制在0-255之间。在这次实验中我原本使用了课本中的标定方法,但是结果却很让人失望,所以最后直接改用截断的方法处理,即:大于255都置为255,小于0的都置为0。进一步说明在结果分析中。
从实验原理我们可以知道,线性滤波原理都一样,也就是说均值滤波器、基本高通滤波器、拉普拉斯滤波器、高频补偿滤波器原理都一样,但是我们可以只用一个函数来实现这几个滤波器吗?当然不行请看下面的分析:
①不管是低通还是高通,线性滤波都是一个原理为什么使用了两个函数分别去实现低通和高通?
答: 低通滤波器的模板各系数之和为1,且他们的取值都在0-1之间,所以处理后得到的加权平均值不会发生溢出的状况,得到结果后可以直接以Mat的形式保存。 而高通滤波器不一样,它的模板各个系数之和为0,有正有负,虽然也是线性滤波,但是处理后可能发生溢出的状况。比如下面的情形:左上为图像,右上为滤波器,滤波后-4x255,发生溢出。如果是线性(均值)滤波器则255/9,不会发生溢出。
说了这些其实就是说高通滤波器要多做一步溢出的处理。由于Mat中如果发生了溢出,那么保存的就不在是计算出的那个负数或者超过255的数。所以我们必须用一个int类型的数组(源程序中用名为imageMat)来保存计算后发生溢出的图像,然后在用算法(源程序中函数名为scale)处理这个发生溢出的图像,让他的所有值在0-255内。②这样一来:低通线性滤波器一个函数,基本高通滤波器和拉普拉斯滤波器可以使用同一个函数,高频补偿滤波器一个函数。其实在真正代码实现的时候基本高通滤波器和拉普拉斯滤波器也分别使用了一个函数,因为拉普拉斯变换后的图像,加上原图像,这样拉普拉斯处理的效果能够得到很好的体现。
③高频补偿滤波器:是对基本线性滤波器的一个线性使用,所以另写函数,调用已经写好的一些函数。
答:这个问题很有价值吗?我认为还是值得一提的,因为我在写程序的时候,这部分还是挺费力的。
为了体现出中值滤波器处理椒盐噪声的强大功能,另写了一个函数Mat addSaltAndPepperNoise(Mat image_in, float rate = 0.2);
来给图像imag_in加上椒盐噪声,然后返回出来。
Mat Spafilt::laplacian(Mat &image_in, int id);
Image_in
是需要传进去的待处理图片,id
是选择用哪个模板处理(在1-4中选),具体模板选择如下: spatial_filtering.cpp文件500多行放在这里不是很好,有需要的同学可以到下载,其实有了设计文件以及详细的注释,自己写实现部分也不是很难。
【spatial_filtering.hpp】#pragma once#include#include using namespace cv;class Spafilt {public: Spafilt(); ~Spafilt(); /* 线性低通滤波器 @image_in:将要处理的图片。 @filter_in[]:使用的滤波器模板。 @sizeOfFilter_in:滤波器大小 @return:处理后的图片 */ Mat linearFilter(Mat &image_in, float filter_in[], int sizeOfFilter_in); /* 给图片加上椒盐噪声 @Image_in:将要处理的图片 @rate:噪声程度,建议(0-0.5) @return: 加上噪声后的图片 */ Mat addSaltAndPepperNoise(Mat image_in, float rate = 0.2); /* 中值滤波器 @image_in:将要处理的图片。 @sizeOfFiter_in;滤波器大小 @return:处理后的图片。 */ Mat medianFilter(Mat &image_in, int sizeOfFilter_in = 3); /* 最大值滤波器 @image_in:将要处理的图片。 @sizeOfFiter_in;滤波器大小 @return:处理后的图片。 */ Mat maxFilter(Mat &image_in, int sizeOfFilter_in = 3); /* 最小值滤波器 @image_in:将要处理的图片。 @sizeOfFiter_in;滤波器大小 @return:处理后的图片。 */ Mat minFilter(Mat &image_in, int sizeOfFilter_in = 3); /* 基本高通滤波器 @image_in:将要处理的图片。 @filter_in[]:使用的滤波器模板。 @sizeOfFilter_in:滤波器大小 @return:处理后的图片 */ Mat basicHighPassFilter(Mat &image_in, float filter_in[], int sizeOfFilter_in); /* 罗伯特算子 @image_in:将要处理的图片 @return:处理后的图片 */ Mat roberts(Mat &image_in); /* prewitt算子 @image_in:将要处理的图片 @return:处理后的图片 */ Mat prewitt(Mat &image_in); /* Sobel算子 */ Mat sobel(Mat &image_in); /* @image_in:将要处理的图片 @id:选择使用哪个模板处理,id应该是1-4中的某一整数,详见实验报告。 @return: Laplacian处理后的图片 */ Mat laplacian(Mat &image_in, int id); /* 高频补偿滤波器 @k;高频补偿加模板的权重,默认为1 */ Mat highBoostFilter(Mat &image_in, float k = 1); /* @原本是一个协助我调试程序的函数 @但是最终它担任了使用截断方式标定的任务 @在Mat scale(int k = 255);中调用了 */ Mat Debug();private: Mat imageSource;//待处理的图片 Mat imageAfterBorderProcess;//对边缘进行处理后的图片。 int* imageMat;//存放经过某些处理后,灰度值超过0-255区间的图片,等待后续处理或应用 int filterSize;//滤波器大小 float *filter;//滤波器模板 /* 设置滤波器大小及模板,这里只考虑方形的滤波器(长宽相等) @size_i:滤波器大小,只能是方形滤波器,传入任一边长度 @fil:滤波器模板 */ void setFilter(int size_i, float *fil); /* 设置滤波器大小这里只考虑方形的滤波器(长宽相等) @size_i:滤波器大小,只能是方形滤波器,传入任一边长度 */ void setFilterSize(int size_i); /* 设置将要处理的图片 @image_i:将要处理的图片 */ void setImage(Mat &image_i); /* 对图像的边缘进行处理 * 处理的是imageSource图片 * 处理后的结果存放在imageAfterBorderProcess中 * 采用镜像处理办法,角落处的值设为128 */ void borderProcessing(); /* * 用来求两幅图像的带权的差或者和, * 可以在图像和图像或图像和数组之间运算 * 用一个系数来控制加或者减或者其他系数 * 结果放在数组imageMat中 @coefficient:系数,决定两幅图像之间进行怎么样的操作 @image_in: 若插入该参数,则进行imageSource和image_in之间的运算, 否则进行imageSource和imageMat之间运算 */ void addOrSubtractOfTwoImage(float coefficient, Mat* image_in = NULL); /* * 使用线性滤波器对图片进行滤波 * 由于高通滤波器模板处理后灰度值有可能溢出,所以结果放在imageMat中,待进一步处理 * 使用私有变量中的filter对imageSource进行滤波 */ void preHighPassFilter(); /* 用来将数组内的所有的灰度值标定到指定灰度区间并以Mat的形式返回出来 不修改数组内容 @参数k:表示标定的上界 下界为零 @return:返回标定后的图像 */ Mat scale(int k = 255); /* 非线性高通3x3滤波器 @filterR:大小为3x3的滤波器模板 @filterC:大小为3x3的滤波器模板 @return:处理后经过标定的图像 */ Mat nonLinearHighPass3x3filter(float* filterR, float* filterC);};
【main.cpp】
#include "spatial_filtering.h"int main(){ Mat image = imread("pic.jpg", CV_LOAD_IMAGE_GRAYSCALE); //被图片读入折磨的情况。 //验证边缘处理的正确性 //验证加和标定的正确性。 //数据类型 imshow("source_image", image); Spafilt spt; //线性低通滤波器 float filter[9]; for (int counter = 0; counter < 9; counter++) filter[counter] = (float)1 / 9; imshow("linearFilter",spt.linearFilter(image, filter, 3)); //中值滤波器 Mat image_noise = spt.addSaltAndPepperNoise(image, 0.2); imshow("beforeMedaiFiltering", image_noise); imshow("afterMedaiFiltering", spt.medianFilter(image_noise, 3)); //最大值滤波器 imshow("maxFilter", spt.maxFilter(image,3)); //最小值滤波器 imshow("mixFilter", spt.minFilter(image, 3)); //基本高通滤波器 float highFilter[9] = { 1, 1, 1, 1, -8, 1, 1, 1, 1}; imshow("BasicHighPassFilter", spt.basicHighPassFilter(image, highFilter, 3)); //Roberts交叉算子 imshow("Roberts", spt.roberts(image)); //prewitt算子 imshow("Prewitt", spt.prewitt(image)); //Sobel算子 imshow("Sobel", spt.sobel(image)); //Laplacian锐化处理 imshow("Laplacian", spt.laplacian(image, 3)); //高频补偿滤波器 imshow("highBoost", spt.highBoostFilter(image, 1)); waitKey(0); return 0;}
刚开始标定使用了是课本中介绍的方法,原理如下:
就是找出最大值和最小值, min(f)就是最小值,max(fm)就是极差,当f为最大值的时候,fm = max(fm).这样fs = k. 当f = min(f)的时候fs = 0.这样整个图像的灰度值就控制在0-k之间了。 但是我处理后所有用了标定处理的图像显得非常灰蒙蒙的,效果不是很好,像下面这样: 上为原图,下为高频补偿处理后的图像 仔细分析,出现这个现象的原因很可能是,上式中max(fm)非常大,然后f-fm能够达到max(fm)的像素个数又是极个别的。所以导致图像处理以后灰度值集中在了128附近。导致上述结果。所以使用了在图像标定部分说的截断的方法。【原图像】
【均值滤波】 【椒盐噪声】 【中值滤波器】 【最大值滤波器】 【最小值滤波】 【基本高通滤波】