高斯模糊
高斯模糊是一种可以让图像过渡平滑的算法,不保留边缘。
实现步骤:
1.输入模糊半径R和标准差σ
2.根据R和σ和二维正态函数生成一个边长为2R+1的权值方阵,方阵中心坐标为(0,0)
3.对图像的每一个像素p进行处理,以p为中心选择半径为2R+1的正方形,用正方形中的RGB分量分别和权值方阵对应位置相乘然后相加,得到模糊后的像素p’
详细步骤:
1.输入模糊半径R和标准差σ
这个是最难解释的,但是大家都懂,就是两个数字R取正整数,σ可以取0.8R。这两个参数可以决定最终的模糊效果。R越大中心点像素可以受到更远像素的影响。σ值越大,周围的像素对中心像素影响越大。
2.假设R=2,σ=1.6,建造一个5*5的方阵.
现在方阵建好了,中心点是(0,0),左上角坐标是(-2,-2),下面要根据二维的正态分布函数(即二维高斯函数)填写权值了,二维高斯函数如下:
R=2,σ=1.6,π≈3.1415,e≈2.71828
下面计算(-2,-2)的值:
将这些已知量带入G(x,y)
G(-2,-2)=1/(2*3.1415*1.6*1.6)*2.71828^(((-2)*(-2)+(-2)*(-2))/(2*1.6*1.6))≈0.0105
计算(-1,-2)的值:
G(-1,-2)=1/(2*3.1415*1.6*1.6)*2.71828^(((-1)*(-1)+(-2)*(-2))/(2*1.6*1.6))≈0.0227
。。。
。。。
计算(2,2)的值:
G(2,2)=1/(2*3.1415*1.6*1.6)*2.71828^(((2)*(2)+(2)*(2))/(2*1.6*1.6))≈0.0105
填写完毕,得到的方阵如下:
到了这里,这个高斯方阵已经计算完毕了,但是我们想要的是权值方阵,这个方阵中的所有权值之和大约为0.8686,并不等于1,如果使用这个方阵做权值,最终得到的图片经过了高斯模糊,但是亮度会比原图暗一些,为了不让处理后的图像变暗,把方阵中的每一个权值除以0.8686,这样,他们的和就等于1了,图像就不会变暗了,计算后,我们得到最终的权值方阵:
3.对图像的每一个像素p进行处理,以p为中心选择半径为2R+1的正方形,用正方形中的RGB分量分别和权值方阵对应位置相乘然后相加,得到模糊后的像素p’
众所周知,计算机通过RGB三原色合成其他各种颜色。
一组RGB可以表示一个像素。
一张平面图片,是由w*h个像素组成的,w图像宽度,h图像高度。一张平面图像是由w*h组RGB组成的。
对于图像的大多数像素点x,y而言,都可以找到一个R*R的方阵,(x,y)在方阵中央。
例如下面这张图片(如果侵犯了版权,请及时联系我,本人QQ:79221571,立刻进行修改):
从这里面可以选择许多5*5的像素方阵,某个颜色方阵如下:
这里虽然用颜色展示了,其本质是5*5*3个byte型数字。其中25个R分量,25G分量,25个B分量。假设其红色分量方阵如下:
sum=0.0121*20+0.0261*30+...+0.0261*94+0.0121*15.
将sum值填到一个新的图片对应位置中心,也就是69的位置。
边缘处可能不能找到一个5*5的像素方阵,这时用它的对称位置补全。
public static int[] gaussianBlur(int[] src,int w,int h,int r,double sigma2){
double kernel[]=gaussianBlurkernel(r, sigma2);
int side=(r<<1)|1;
double weight;
int res[]=new int[src.length];
int x,y;
double R,G,B;
int rr,gg,bb,color;
for(int i=0;i<h;i++){
for(int j=0;j<w;j++){
//中心点坐标(j,i)
R=0f; G=0f; B=0f; 这里我们使用的是灰度图,只计算B即可
B=0f;
for(int p=-r;p<=r;p++){
for(int q=-r;q<=r;q++){
weight=kernel[(p+r)*side+q+r];
y=i+p;
x=j+q;
if(x<0||x>=w){
x=2*j-x;
}
if(y<0||y>=h){
y=2*i-y;
}
color=src[y*w+x];
R+=((color>>16)&0xff)*weight;
G+=((color>>8)&0xff)*weight;
B+=(color&0xff)*weight;
}
}
rr=(int)R;gg=(int)G;bb=(int)B;
bb=(int)B;
res[i*w+j]=(bb<<16)|(bb<<8)|bb;
//res[i*w+j]=bb;
}
}
return res;
}
public static double[] gaussianBlurkernel(int r,double sigma2){
int side=(r<<1)|1;
double[] kernel=new double[side*side];
double sigma2X2=sigma2*2f;
double sigma2X2XPI=sigma2X2*Math.PI;
double w,sw=0;
for(int i=0;i<side;i++){
for(int j=0;j<side;j++){
double x=j-r;
double y=i-r;
w=Math.exp(-(x*x+y*y)/sigma2X2)/sigma2X2XPI;
kernel[i*side+j]=w;
sw+=w;
}
}
for(int i=0;i<kernel.length;i++){
kernel[i]/=sw;
}
return kernel;
}
终于写完了,图片真难做!!!!!看效果图吧,取R=10,σ=8