首页 > 解决方案 > 高斯模糊较高半径使图像变暗

问题描述

我在 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 模糊: 模糊半径 2

以半径 7 模糊: 模糊半径 7

为什么用半径 7 模糊它会使图像变暗?公式中是否缺少某些内容或我遗漏了什么?

标签: javagaussiangaussianblur

解决方案


推荐阅读