一、定义:
高斯模糊(英语:Gaussian Blur),也叫高斯平滑。
通常用它来减少图像噪声以及降低细节层次。这种模糊技术生成的图像,其视觉效果就像是经过一个毛玻璃在观察图像,这与镜头焦外成像效果散景以及普通照明阴影中的效果都明显不同。高斯平滑也用于计算机视觉算法中的预先处理阶段,以增强图像在不同比例大小下的图像效果(参见尺度空间表示以及尺度空间实现)。 从数学的角度来看,图像的高斯模糊过程就是图像与正态分布做卷积。由于正态分布又叫作高斯分布,所以这项技术就叫作高斯模糊。图像与圆形方框模糊做卷积将会生成更加精确的焦外成像效果。由于高斯函数的傅里叶变换是另外一个高斯函数,所以高斯模糊对于图像来说就是一个低通滤波器。(解释来源于百度百科https://baike.baidu.com/item/%E9%AB%98%E6%96%AF%E6%A8%A1%E7%B3%8A)
二、理论原理(来源于百度百科)
高斯模糊是一种图像模糊滤波器,它用正态分布计算图像中每个像素的变换。N维空间正态分布方程为
在二维空间定义为
其中r是模糊半径,σ是正态分布的标准偏差。在二维空间中,这个公式生成的曲面的等高线是从中心开始呈正态分布的同心圆。分布不为零的像素组成的卷积矩阵与原始图像做变换。每个像素的值都是周围相邻像素值的加权平均。原始像素的值有最大的高斯分布值,所以有最大的权重,相邻像素随着距离原始像素越来越远,其权重也越来越小。这样进行模糊处理比其它的均衡模糊滤波器更高地保留了边缘效果,参见尺度空间实现。
理论上来讲,图像中每点的分布都不为零,这也就是说每个像素的计算都需要包含整幅图像。在实际应用中,在计算高斯函数的离散近似时,在大概3σ距离之外的像素都可以看作不起作用,这些像素的计算也就可以忽略。通常,图像处理程序只需要计算
的矩阵就可以保证相关像素影响。对于边界上的点,通常采用复制周围的点到另一面再进行加权平均运算。
......(其余请自行查看百度百科https://baike.baidu.com/item/%E9%AB%98%E6%96%AF%E6%A8%A1%E7%B3%8A)
三、实现原理
先确定模糊半径,然后对每一个像素都取周边像素的平均值。
模糊半径越大,图像就越模糊。从数值角度看,就是数值越平滑。
关于权重分配问题:
1、局部加权平均;
2、基于正态分布。
关于算力问题:使用多线程加速。
四、实现代码
package com.young;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class demo {
public static void main(String[] args) {
try {
long l = System.currentTimeMillis();
BufferedImage image = ImageIO.read(new File("beb9894fc1a505976f996163f8c20361.jpg"));
BufferedImage image1 = new demo().GaussianBlur(image, 20);
ImageIO.write(image1, "jpg", new File("a.jpg"));
l = System.currentTimeMillis() - l;
System.out.println(l);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 基于加权平均的权重分配(也可以基于正态分布等等)
*
* @param image 图像类
* @param index 模糊半径
*/
BufferedImage GaussianBlur(BufferedImage image, int index) {
int width = image.getWidth();
int height = image.getHeight();
BufferedImage result = new BufferedImage(width, height, 1);
System.out.println("宽度:" + width);
System.out.println("高度:" + height);
/**
* 嵌套的for循环可以使用多线程进行加速处理
*/
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
result.setRGB(i, j, getRGBAvg(image, i, j, index));
return result;
}
int getRGBAvg(BufferedImage image, int x, int y, int index) {
int RGBAvg = 0;
int rAvg = 0;
int gAvg = 0;
int bAvg = 0;
int[] point = new int[(index * 2 + 1) * (index * 2 + 1)];
int size = 0;
for (int i = Math.max(x - index, 0); i < Math.min(x + index + 1, image.getWidth()); i++) {
for (int j = Math.max(y - index, 0); j < Math.min(y + index + 1, image.getHeight()); j++) {
point[size++] = image.getRGB(i, j);
}
}
for (int i : point) {
rAvg += (i >> 16) & 0xff;
gAvg += (i >> 8) & 0xff;
bAvg += i & 0xff;
}
RGBAvg |= rAvg / size << 16;
RGBAvg |= gAvg / size << 8;
RGBAvg |= bAvg / size;
return RGBAvg;
}
int getR(BufferedImage image, int x, int y) {
return (image.getRGB(x, y) >> 16) & 0xff;
}
int getG(BufferedImage image, int x, int y) {
return (image.getRGB(x, y) >> 8) & 0xff;
}
int getB(BufferedImage image, int x, int y) {
return image.getRGB(x, y) & 0xff;
}
}