基于正态分布的图片高斯模糊算法
前言:
? 先來看看下面這張圖,我把一張圖進行了二等份了,左邊是經過高斯模糊過的,右邊是原圖。
??
圖-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.卷積圖像處理
總結
以上是生活随笔為你收集整理的基于正态分布的图片高斯模糊算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构:关于AVL树的平衡旋转详解
- 下一篇: 操作系统:基于页面置换算法的缓存原理详解