高斯模糊(Gausscian Blur,亦称高斯平滑)是一种基于二维正态分布的的加权模糊,用于图像去噪及弱化图像细节,相比平均模糊暴力地将周围像素平等对待,高斯模糊利用正态分布函数对周围像素进行评价,距离中心点较远的像素对中心点影响较小。高斯模糊是一种低通滤波器。(参考维基百科。)
一、卷积运算
图像的卷积运算是特殊的领域运算,从某个像素点开始依次向后运算,比较像卷起地毯的动作。
模板:参与运算的矩阵,以此矩阵对目标图像进行处理。
核(kernel):基数正方形矩阵,是一个权矩阵。
卷积运算:权矩阵在目标图像上的加权运算。
二、高斯函数
N维正态分布:
N=2时,二维正态分布如下:
其中u、v的取值范围为[-r,r],r为模糊半径。根据公式可计算出kernel,即卷积模板。
此时得到的矩阵需要进行归一化处理,使模板的总和基本等于1。归一化方法很简单,直接计算矩阵内所有元素总和,再分别将各个元素除以此总和即可。
// G(x,y)=[1/(2*PI*sigma^2)]*e^[-((x^2+y^2)/(2*sigma^2))] // x,y->[-radius,radius) public float[][] gaussian2DKernel(final int radius, final float sigma) { final int length = 2 * radius; final float[][] matric = new float[length + 1][length + 1]; final float sigmaSquare2 = 2 * sigma * sigma; float sum = 0; for (int x = -radius; x <= radius; x++) { for (int y = -radius; y <= radius; y++) { matric[radius + x][radius + y] = (float) (Math.pow(Math.E, -(x * x + y * y) / sigmaSquare2) / (Math.PI * sigmaSquare2)); sum += matric[radius + x][radius + y]; } } for (int x = 0; x < length; x++) { for (int y = 0; y < length; y++) { matric[x][y] /= sum; } } return matric; }
当r=3,sigma=0.84089642时,模板如下:
0.00000067 | 0.00002292 | 0.00019117 | 0.00038771 | 0.00019117 | 0.00002292 | 0.00000067 |
0.00002292 | 0.00078633 | 0.00655965 | 0.01330373 | 0.00655965 | 0.00078633 | 0.00002292 |
0.00019117 | 0.00655965 | 0.05472157 | 0.11098164 | 0.05472157 | 0.00655965 | 0.00019117 |
0.00038771 | 0.01330373 | 0.11098164 | 0.22508352 | 0.11098164 | 0.01330373 | 0.00038771 |
0.00019117 | 0.00655965 | 0.05472157 | 0.11098164 | 0.05472157 | 0.00655965 | 0.00019117 |
0.00002292 | 0.00078633 | 0.00655965 | 0.01330373 | 0.00655965 | 0.00078633 | 0.00002292 |
0.00000067 | 0.00002292 | 0.00019117 | 0.00038771 | 0.00019117 | 0.00002292 | 0.00000067 |
卷积运算Java代码:
public BufferedImage convolution(final BufferedImage image, final float kernel[][]) { final int width = image.getWidth(); final int height = image.getHeight(); final int radius = kernel.length / 2; final BufferedImage retImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { double sumA = 0; double sumR = 0; double sumG = 0; double sumB = 0; for (int x = i - radius; x <= i + radius; x++) { for (int y = j - radius; y <= j + radius; y++) { final int posX = x < 0 ? 0 : x >= width ? width - 1 : x; final int posY = y < 0 ? 0 : y >= height ? height - 1 : y; final int color = image.getRGB(posX, posY); final int a = (color >> 24) & 0xff; final int r = (color >> 16) & 0xff; final int g = (color >> 8) & 0xff; final int b = color & 0xff;final int kelX=x - i + radius; final int kelY=y - j + radius; sumA += kernel[kelX][kelY] * a; sumR += kernel[kelX][kelY] * r; sumG += kernel[kelX][kelY] * g; sumB += kernel[kelX][kelY] * b; } } final int blurColor = (((int) sumA)<<24) | (((int) sumR) << 16) | (((int) sumG) << 8) | ((int) sumB); retImage.setRGB(i, j, blurColor); } } return retImage; }</pre>
值得注意的是,各个颜色通道必须分别处理。
原图:
效果图:
边缘处理:矩阵卷积运算必然涉及边缘像素处理问题。在对边缘像素加权求和时,模板覆盖到边界之外,实际应用最多的有三种方法:1)舍弃这些像素,即生成图片减少一圈宽为radius(模糊半径)的边框;2)原封不动地保留这些像素,即生成图片有一圈宽为radius(模糊半径)的边框;3)使用最近的像素或者另一边的像素填充使其满足运算条件。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于