Я реализовал Размытие по Гауссу в Java, похоже, он работает на меньших радиусах, но не на больших. Я не уверен, почему на больших радиусах изображение темнеет, я следовал той же формуле и шагам, чтобы применить размытие. Генерация матрицы размытия и ее применение к исходному изображению и установка значения пикселя в качестве суммы результата умножения матрицы изображения на матрицу размытия. Я добавил код, который написал ниже:
public class GaussianBlur extends ImageFilter {
private int radius;
private double sigma;
public GaussianBlur(String imageFilename, int radius) {
super(imageFilename);
this.radius = radius;
this.sigma = ((2.0 * radius) + 1.0) / 2.0;
}
@Override
public void applyFilter() throws IOException {
init();
Matrix<Double> gaussianMatrix = getGaussianMatrix();
Matrix<Color> imageMatrix, weightedImageMatrix;
Color weightedPixelSum;
for(int i = 0; i < getWidth(); i++) {
for(int j = 0; j < getHeight(); j++) {
imageMatrix = getImageMatrix(i, j);
weightedImageMatrix = multiplyImageMatrixWithWeight(imageMatrix, gaussianMatrix);
weightedPixelSum = getWeightedGaussianBlurValue(weightedImageMatrix);
getFilter().setRGB(i, j, weightedPixelSum.getRGB());
}
}
}
private Matrix<Double> getGaussianMatrix() {
Matrix<Double> gaussianMatrix = new Matrix<>(Double.class, radius);
double weightedSum = 0.0;
int matrixI = 0, matrixJ;
double gaussianValue;
for(int i = -radius; i <= radius; i++) {
matrixJ = 0;
for(int j = -radius; j <= radius; j++) {
gaussianValue = getGaussianValue(i, j);
weightedSum += gaussianValue;
gaussianMatrix.setValue(matrixI, matrixJ, gaussianValue);
matrixJ++;
}
matrixI++;
}
for(int i = 0; i < gaussianMatrix.getMatrix().length; i++) {
for(int j = 0; j < gaussianMatrix.getMatrix()[i].length; j++) {
gaussianMatrix.setValue(i, j, gaussianMatrix.getValue(i, j) / weightedSum);
}
}
return gaussianMatrix;
}
private double getGaussianValue(int x, int y) {
return 1.0 / (2.0 * Math.PI * sigma * sigma) * Math.pow(Math.E, -((x * x) + (y * y)) / (2.0 * (sigma * sigma)));
}
private Color getWeightedGaussianBlurValue(Matrix<Color> weightedImageMatrix) {
int r = 0, g = 0, b = 0;
for(int i = 0; i < weightedImageMatrix.getMatrix().length; i++) {
for(int j = 0; j < weightedImageMatrix.getMatrix()[i].length; j++) {
if(weightedImageMatrix.getValue(i, j) != null) {
r += weightedImageMatrix.getValue(i, j).getRed();
g += weightedImageMatrix.getValue(i, j).getGreen();
b += weightedImageMatrix.getValue(i, j).getBlue();
}
}
}
return new Color(r, g, b);
}
/*
* Multiply each image pixel with its matrix value to get a new matrix with the weighted pixel values.
*/
private Matrix<Color> multiplyImageMatrixWithWeight(Matrix<Color> imageMatrix, Matrix<Double> gaussianMatrix) {
Matrix<Color> weightedImageMatrix = new Matrix<>(Color.class, this.radius);
Color weightedValue;
for(int i = 0; i < weightedImageMatrix.getMatrix().length; i++) {
for(int j = 0; j < weightedImageMatrix.getMatrix()[i].length; j++) {
if(imageMatrix.getValue(i, j) != null) {
weightedValue = new Color(
(int) ((double) imageMatrix.getValue(i, j).getRed() * gaussianMatrix.getValue(i, j)),
(int) ((double) imageMatrix.getValue(i, j).getGreen() * gaussianMatrix.getValue(i, j)),
(int) ((double) imageMatrix.getValue(i, j).getBlue() * gaussianMatrix.getValue(i, j))
);
weightedImageMatrix.setValue(i, j, weightedValue);
} else {
weightedImageMatrix.setValue(i, j, null);
}
}
}
return weightedImageMatrix;
}
/*
* Given the center points (i, j), construct a matrix from the image to blur.
*/
private Matrix<Color> getImageMatrix(int i, int j) {
Matrix<Color> imageMatrix = new Matrix<>(Color.class, radius);
int matrixI = 0, matrixJ;
for(int x = i - radius; x <= i + radius; x++) {
matrixJ = 0;
for(int y = j - radius; y <= j + radius; y++) {
if(x > -1 && y > -1 && x < getOriginal().getWidth() && y < getOriginal().getHeight()) {
imageMatrix.setValue(matrixI, matrixJ, new Color(getOriginal().getRGB(x, y)));
} else {
imageMatrix.setValue(matrixI, matrixJ, null);
}
matrixJ++;
}
matrixI++;
}
return imageMatrix;
}
private class Color {
private int r, g, b;
public Color(int r, int g, int b) {
this.r = r;
this.g = g;
this.b = b;
}
public Color(int rgb) {
this((rgb >> 16) & 0xff, (rgb >> 8) & 0xff, rgb & 0xff);
}
public int getRed() {
return r;
}
public int getGreen() {
return g;
}
public int getBlue() {
return b;
}
public int getRGB() {
return (r << 16) | (g << 8) | b;
}
@Override
public String toString() {
return "(" + r + "," + g + "," + b + ")";
}
}
private class Matrix<T> {
private T[][] matrix;
public Matrix(Class<T> clazz, int radius) {
int length = (2 * radius) + 1;
matrix = (T[][]) Array.newInstance(clazz, length, length);
}
public T getValue(int i, int j) {
return matrix[i][j];
}
public void setValue(int i, int j, T value) {
matrix[i][j] = value;
}
public T[][] getMatrix() {
return matrix;
}
}
}
Класс ImageFilter - это просто абстрактный класс с двумя экземплярами BufferedImage (один для исходного изображения и один для размытого изображения) и функцией displayImage
просто отображает изображение в диалоговом окне сообщения.
Основной метод, использующий этот класс:
public static void main(String[] args) throws IOException {
String filename = "res" + File.separator + "TajMahal.jpeg";
GaussianBlur gaussianBlur = new GaussianBlur(filename, 2);
gaussianBlur.applyFilter();
gaussianBlur.displayImage();
}
А ниже приведены полученные изображения
Исходное изображение:
Размыто с радиусом 2:
Размыто с радиусом 7:
Почему размытие с радиусом 7 затемняет изображение? Чего-то не хватает в формуле или чего-то, что я пропустил?