java 高斯模板与高斯模糊

本文用到了卷积的内容,如有了解较少的同学建议转到java图像处理(卷积,强调边缘,平滑与高斯模糊)先了解一下

预备知识

高斯模糊的概念

高斯模糊(Gaussian Blur),是常用的用来减少噪声的算法。其实质上是图像与正态分布的卷积,而正态分布又叫做高斯分布,故而名为高斯模糊

在这里插入图片描述

高斯模糊的原理
像素重置

模糊的过程即将每个像素值进行重置的过程,重置的一般过程即为将每一个像素设置成周围像素的平均值(算数平均或加权平均),如以下像素组
在这里插入图片描述
这个像素组的中间为8,其余周围为1
假定中心点的元素对周围元素无影响,那么我们需要用来求平均值的卷积核为
在这里插入图片描述
卷积一下
在这里插入图片描述
这样,中间的值就从较大的8变成了较小的16/9,相当于是平滑了中间值,因此使用上面卷积核来进行模糊的算法也叫做平滑模糊
当然我们也可以以卷积核作为权来进行加权平均,如下面我们使用的高斯模糊的卷积核就是加权平均的一种

使用范围为3,5,7,9的平均值卷积核来进行平滑模糊的效果如图所示
在这里插入图片描述
很明显,随着范围的增大,模糊的效果越来越明显,但是平滑模糊由于权重一致,虽然有一定的模糊效果,但是对噪声的处理不是很好,如果我们找到了一种权重的定义的话,可能会对我们的模糊处理有着更有益的效果。

很容易想到的是将权重与距离联系起来,距离中心元越近权重越高,距离中心元越远权重越低。
如何分辨中心元素和周围元素的距离关系?
一种常见的衡量方法为

正态分布(也叫高斯分布)

一维的正态分布我们已经很常见了
在这里插入图片描述
在这里插入图片描述
这种中心高,两侧低的算法正好可以用于我们对距离的判定
但是,由于图像是二维的,因此一维的正态分布在这里不适用

我们将x换成(x^2 + y^2)的开方,即可将一维的正态曲线旋转画到二维中
在这里插入图片描述
由于我们将(0,0)点定义成中心点,这样公式中的μ值取0,公式即为在这里插入图片描述
有了这个公式,我们就可以根据公式生成一个卷积核,然后去和像素区域进行卷积,这样得到的就是加权平均过后的中心值了
根据正态分布产生的卷积核我们叫做高斯模板

高斯模板代码(java)
		 //设置一个数组存储高斯模板,其中size为模板的大小(也叫做卷积核范围)
		 double[][] gaussModel = new double[size][size]; 
		 //设置图片中心参数
		 int CenterX = (size-1)/2;
		 int CenterY = CenterX;  
		 //临时中间量
		 double part;
		 //高斯模板的总和
		 double sum = 0;
		 //定义一个合适的sigma值
		 double sigma = size / 3.0f;
		 for(int i = 0; i< size; ++i){
			 //根据高斯公式计算高斯模板
			 	for(int j = 0; j < size; ++j){
			 	   //首先产生指数值中有关x,y的内容
			 	   part = (i - CenterX) * (i - CenterX) + (j  - CenterY) * (j - CenterY);
			 	   //然后进行高斯值的计算,并赋到高斯模板的数组中
				   gaussModel[i][j] = (double)(Math.exp( - part / (2 * sigma * sigma) ) 
						   / Math.sqrt(2 * Math.PI * sigma * sigma));
				   //将高斯值加到总和中
				   sum += gaussModel[i][j];
			 	}
		 }
		 // 归一化,为了使处理后的图像与原图亮度相同
		 for(int i = 0; i< size; ++i){
			 for(int j = 0; j < size; ++j){
				 //将所得高斯值除以sum值,使其缩到1内,即为归一化
				 gaussModel[i][j] = (double) (gaussModel[i][j] / sum);
			 }
		 }		 

附:生成的3 * 3与5 * 5的高斯模板
3x3高斯模板
5x5高斯模板

边缘处理

暂时想到的是可以将原图先四周围临时补上一圈无意义的像素点,但是补什么样的点暂时我还没有想出来,在这里先补上了黑色点,像素点宽度为size/2(例如3 * 3的卷积核补充一圈宽度为1的像素点),这样在处理图像时就可以将整个图像进行处理,最后再去掉补上的点即可。

代码请见下面高斯模板内的代码

下面是效果
处理之前的边缘,是有很明显的没有处理的边界的
在这里插入图片描述
处理之后的边缘,很明显是被处理过的,补的是黑色边框(根据周围颜色来补边框的算法暂时还没研究出来,如果有好的解决方法欢迎各位支援!)
在这里插入图片描述

高斯模糊的代码实现

这里实现的是彩色图像的高斯模糊,因此我们需要对原图的rgb值进行提取,然后分别对r,g,b进行卷积处理后绘出(也可以理解成使用了3 * 3 * 3的一个三维卷积核)
请仔细阅读注释内容,注释中有详细的代码解释

 		 //设置临时边缘的宽度
		 int tempWidth = size/2;
		 //设置一个数组存储含边缘的图片数据,其中边缘因为是上下左右均要补边,因此是2*tempWidth
		 int[][] tempImg = new int[width+2*tempWidth][height+2*tempWidth]; 
		 //将横着的边缘补上
		 for(int x = 0;x < width+2*tempWidth;x++){
			 for(int y = 0;y < tempWidth;y++){
				 //将上下的边缘补上
				 tempImg[x][y] =0;
				 //height+2*tempWidth-y-1计算下面需要补充的边缘的y值位置,下同,不再赘述
				 tempImg[x][height+2*tempWidth-y-1] =0;
			 }
		 }
		 //将竖着的边缘补上
		 for(int y = 0;y < height+2*tempWidth;y++){
			 for(int x = 0;x < tempWidth;x++){
				 tempImg[x][y] = 0;
				 tempImg[width+2*tempWidth-x-1][y] =0;
			 }
		 }
		 //将原有图像传到新数组中等待处理,其中将原有图像向右下角移动tempWidth个单位即可将原图赋到新图中
		 for(int x = 0;x < width;x++){
			 for(int y = 0;y < height;y++){
				 tempImg[x+tempWidth][y+tempWidth] = rgbOfImg[x][y];
			 }
		 }
		 //下面开始搞卷积算法
		//初始化rgb数组
		R = new int[size][size];
		G = new int[size][size];
		B = new int[size][size];
		//遍历图像的二维数组进行处理
		for(int x = 0;x < width+2*tempWidth-size+1;x++){
			for(int y = 0;y < height+2*tempWidth-size+1;y++){
				//一定要在循环内部进行初始化0,这样才能每次有不同的值
				int resultOfR = 0;
				int resultOfG = 0;
				int resultOfB = 0;
				//将格子的rgb值都取出,便于之后的卷积操作
				for(int i = 0;i < size;i++){
					for(int j = 0;j <size;j++){
						//将该点的ARGB信息取出,放到变量中待操作
						int argb = tempImg[x+i][y+j];
						//分段获取其R,G,B信息
						//int变量共4位32字节,0位对应透明度(A),1位对应R值,2位对应G值,3位对应B值
						//>>操作:将二进制代码向右移动,左边空位根据符号补充,正号为0,负号为1,右边超过范围的全部舍弃
						//&:二进制位与运算符,只有两个变量对应值均为1时该位才返回1,0xff表示全为1的十六进制数(11111111),因此任何与0xff进行位与的结果均为其本身
						//先移位后取位与可以将不同值对应的位信息取出,位与的意义是只取32字节的后8字节
						R[i][j] = argb>>16 & 0xff;
						G[i][j] = argb>>8  & 0xff;
						B[i][j] = argb     & 0xff;
					}
				}
				//分别对R,G,B进行卷积操作,对应相乘后加起来
				for(int i = 0;i < size;i++){
					for(int j = 0;j < size;j++){
						resultOfR += (int)(gaussModel[i][j]*R[i][j]);
					}
				}
				for(int i = 0;i < size;i++){
					for(int j = 0;j < size;j++){
						resultOfG += (int)(gaussModel[i][j]*G[i][j]);

					}
				}				
				for(int i = 0;i < size;i++){
					for(int j = 0;j < size;j++){
						resultOfB += (int)(gaussModel[i][j]*B[i][j]);
					}
				}
				//如果超过了界限,将其按照最大值或最小值处理
				if(resultOfR > 255)resultOfR = 255;
				if(resultOfR < 0)resultOfR = 0;
				if(resultOfG > 255)resultOfG = 255;
				if(resultOfG < 0)resultOfG = 0;
				if(resultOfB > 255)resultOfB = 255;
				if(resultOfB < 0)resultOfB = 0;
				
				//将卷积得出的高斯模糊的灰度值传到中间元中
				//根据该argb值创建颜色对象
				Color color = new Color(resultOfR, resultOfG, resultOfB);
				//设置颜色
				graphics2.setColor(color);
				//画像素点,将点向左上平移以实现边框的去除
				graphics2.drawLine(x+size/2-tempWidth, y+size/2-tempWidth, x+size/2-tempWidth, y+size/2-tempWidth);
			}
		}

效果(左为3 * 3,右为5 * 5)
在这里插入图片描述
在这里插入图片描述
附原图
在这里插入图片描述
在这里插入图片描述

发布了36 篇原创文章 · 获赞 11 · 访问量 2906

猜你喜欢

转载自blog.csdn.net/yeweij226/article/details/99817808