I implemented Gaussian Blur in Java, it seems to work on smaller radiuses but not on bigger ones. I'm not sure why on bigger radiuses the image darkens, I followed the same formula and the steps to apply the blur. Generating the blur matrix and applying it on the original image, and setting the pixel value to be the sum of the result of multiplying the image matrix with the blur matrix. I added the code I wrote below:
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;
}
}
}
The class ImageFilter is just an abstract class with two instances of BufferedImage (one for the original image and one for the blurred image), and the displayImage
function just displays the image in a message dialog.
The main method using this class is
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();
}
And below are the resulting images
How come blurring it with radius 7 is darkening the image? Is there something missing in the formula or something that I have missed?