基于正态分布的图片高斯模糊算法

前言:

  先来看看下面这张图,我把一张图进行了二等份了,左边是经过高斯模糊过的,右边是原图。

  

图-1 高斯模糊效果对比图


概述:

  高斯模糊也叫做高斯平滑,是一种图像平滑处理的技术。高斯模糊算法的原理是选取一个中心点,以及一个半径周围的所有点,再计算这些像素点的平均值,这个值就是目前这个中心点的值了。这样实现的效果是可以降低图像中的噪音干扰,以达到忽略图像中的细节的目的。


本文链接:http://blog.csdn.net/lemon_tree12138/article/details/50425793 -- Coding-Naga
                                                                 --转载请注明出处

原理说明:

  上面说到高斯模糊是计算某些像素点的平均值,那么究竟是什么样的呢?看图-2。


图-2 像素点均值计算

  现在我们假设我们就是按照上面的图形进行选取一些像素点的,可是我们的实际图像的像素可不止这些。所以,这里就涉及到另一个知识点了:卷积。不要被卷积这个字面上的词语所惊吓,如果你觉得书面上卷积晦涩难懂,那么你可以看看下面这幅图,它大致描绘了在本文中使用到的卷积基础。

  从下面的图解中,我们可以看到,就像是有一块固定大小的区域在沿着横向或是纵向滑动一样。是的,这里我们是以亮绿色为中心点,包含一个半径为1的周围点进行向右和向下的平移。这个很像在计算机网络中学到的滑动窗口一样。


图-3 卷积概念图解(部分)

逻辑实现:

1.朴素的高斯模糊算法

  如上面的图-2和图-3,我们知道模糊一张图片的做是可以卷积计算每个点的平均值。那么现在我们就选取以9个点为一个单位模块进行卷积计算,再求其平均值。效果如下图-4.


图-4 朴素高斯模糊效果对比图

  从效果图中我们的确是可以看出有一些模糊的效果,不过感觉上像是图片进行了一定像素上的滑移。而且,图像很暗。结论:算法很糟糕。

2.基于正态分布的高斯模糊算法

  上面朴素的做法是让中心点和它周围的点具有相同数值的权重。这样是不合理的,为什么?

  我们知道图片是连续的,距离越近的像素点,数值应该是更相近的。那么,朴素高斯模糊中简单平均的做法肯定就不合理了。

  所以这里我们是使用正态分布来分配权重。正态分布的分布图如下图-5所示:


图-5 一维正态分布图

  这幅图相信大家都并不陌生,高中时的课本上就有的。不过因为我们的图片是一个二维的图像,那么单纯的一维还是解决不了问题,下面看看一下二维的高斯分布图吧。


图-6 二维高斯分布图

  图-6中的说明之所以修改成了高斯分布图,是因为高斯模糊中使用的正态分布,跟我们在高中时期学习的正态分布公式有一些不一样。

  一维高斯函数:


  二维高斯函数:


  二维高斯函数的实现如下:

/**
     * 二维高斯函数
     * 
     * @param n
     *      二维高斯的范围[-n, n]
     * @param σ
     *      标准方差
     * @return
     *      范围[-n, n]之内的高斯函数值
     */
    public static float[][] getTwoDimenGaussianFunction(int n, float σ) {        
        int size = 2 * n + 1;
        float σ22 = 2 * σ * σ;
        float σ22PI = (float)Math.PI * σ22;
        float[][] kernalData = new float[size][size];
        int row = 0;
        for(int i = -n; i <= n; i++) {
            int column = 0;
            for(int j = -n; j <= n; j++) {
                float xDistance = i * i;
                float yDistance = j * j;
                kernalData[row][column] = (float)Math.exp(-(xDistance + yDistance) / σ22) / σ22PI;
                column++;
            }
            row++;
        }
        return kernalData;
    }
  根据以上内容我们可以编写以下高斯模糊核心算法的Java代码:
public class GaussianBlur implements ImageInterface {
    
    private int radius;
    private int round;
    
    // 高斯函数的权重矩阵
    private float[][] normal_distribution = null;
    
    public GaussianBlur(int _round, int _radius) {
        ... ...
        initEvent(radius, 1.5f);
    }
    
    public static void main(String[] args) {
        GaussianBlur blur = new GaussianBlur(5, 1);
        try {
            blur.gaussianBlur("F:\Wall Paper\9.jpg", "F:\Wall Paper\9-gb.jpg");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 基于正态分布的图片高斯模糊
     */
    public void gaussianBlur(String sourcePath, String targetPath) throws IOException {
        gaussianBlur(sourcePath, targetPath, round, radius);
    }
    
    /**
     * 基于正态分布的图片高斯模糊
     */
    public void gaussianBlur(String sourcePath, String targetPath, int round, int radius) throws IOException {
        BufferedImage bufferedImage = ImageIO.read(new File(sourcePath));
        int height = bufferedImage.getHeight();
        int width = bufferedImage.getWidth();
        
        int matrixLength = 2 * radius + 1;
        int[][] matrix = new int[matrixLength][matrixLength];
        int[] values = new int[matrixLength * matrixLength];
        
        for (int r = 0; r < round; r++) {
            for (int i = 0; i < width / 2; i++) {
                for (int j = 0; j < height; j++) {
                    readPixel(bufferedImage, i, j, values);
                    fillMatrix(matrix, values);
                    bufferedImage.setRGB(i, j, avgMatrix(matrix));
                }
            }
        }
        
        ImageIO.write(bufferedImage, "jpg", new File(targetPath));
    }
    
    /*
     * 初始化任务
     */
    private void initEvent(int n, float σ) {
        normal_distribution = MathUtils.getTwoDimenGaussianSumOne(n, σ);
    }
    
    /*
     * 读取图片上的像素点
     */
    private void readPixel(BufferedImage img, int x, int y, int[] pixels) {
        int radius = (int) ((Math.sqrt(pixels.length) - 1) / 2);
        int raw = 2 * radius + 1;
        int clo = 2 * radius + 1;
        
        int xStart = x - radius;
        int yStart = y - radius;
        int current = 0;
        for (int i = xStart; i < clo + xStart; i++) {
            for (int j = yStart; j < raw + yStart; j++) {
                int tx = i;
                // 边界处理
                if (tx < 0) {
                    tx = -tx;
                } else if (tx >= img.getWidth()) {
                    tx = x;
                }

                int ty = j;
                // 边界处理
                if (ty < 0) {
                    ty = -ty;
                } else if (ty >= img.getHeight()) {
                    ty = y;
                }
                pixels[current++] = img.getRGB(tx, ty);
            }
        }
    }

    /*
     * 将读取的像素RGB值保存到二维数组中
     */
    private void fillMatrix(int[][] matrix, int... values) {
        int filled = 0;
        for (int i = 0; i < matrix.length; i++) {
            int[] x = matrix[i];
            for (int j = 0; j < x.length; j++) {
                x[j] = values[filled++];
            }
        }
    }

    /*
     * 计算平均值重新写入图片
     */
    private int avgMatrix(int[][] matrix) {
        int red = 0;
        int green = 0;
        int blue = 0;
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[i].length; j++) {
                Color color = new Color(matrix[i][j]);
                red += (normal_distribution[i][j] * color.getRed());
                green += (normal_distribution[i][j] * color.getGreen());
                blue += (normal_distribution[i][j] * color.getBlue());
            }
        }
        return new Color(red, green, blue).getRGB();
    }
}

效果图:


图-7 一轮高斯模糊


图-8 三轮高斯模糊


图-9 五轮高斯模糊


图-10 十轮高斯模糊

Ref:

高斯模糊的算法:http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html

图像处理之高斯模糊:http://blog.csdn.net/jia20003/article/details/7234741


注:本文部分图片也是来源于上面的两个博客,在此特作说明。


关联知识点:

1.正态分布

2.卷积图像处理


原文地址:https://www.cnblogs.com/fengju/p/6336021.html