我需要在Java中为3x3、5x5和7x7矩阵实现高斯模糊。如果我错了,你能纠正我吗:


我有一个matrix(M)3x3(中间值为M(0,0)):

1 2 1
2 4 2
1 2 1

我从图像中获取一个像素(P),并为每个最近的像素获取一个像素:

s = M(-1, -1) * P(-1, -1) + M(-1, 0) * P(-1, 0) + ... + M(1, 1) * P(1, 1)

然后除以矩阵的总值:

P'(i, j) = s / M(-1, -1) + M(-1, 0) + ... + M(1, 1)



这就是我的程序所做的全部。我保留极端像素不变。

我的程序:

for(int i = 1; i < height - 1; i++){
    for(int j = 1; j < width - 1; j++){
        int sum = 0, l = 0;
        for(int m = -1; m <= 1; m++){
            for(int n = -1; n <= 1; n++){
                try{
                    System.out.print(l + " ");
                    sum += mask3[l++] * Byte.toUnsignedInt((byte) source[(i + m) * height + j + n]);
                } catch(ArrayIndexOutOfBoundsException e){
                    int ii = (i + m) * height, jj = j + n;
                    System.out.println("Pixels[" + ii + "][" + jj + "]    " + i + ", " + j);
                    System.exit(0);
                }
            }
            System.out.println();
        }
        System.out.println();
        output[i * width + j] = sum / maskSum[0];
    }
}




我从这样的source获得BufferedImage

int[] source = image.getRGB(0, 0, width, height, null, 0, width);


因此,对于此图像:
java - Java:高斯模糊的实现-LMLPHP

结果是这样的:
java - Java:高斯模糊的实现-LMLPHP

您能描述一下我的程序怎么了吗?

最佳答案

首先,您用于计算源数组中索引的公式是错误的。图像数据一个像素行一个像素行地存储在阵列中。因此,给定xy的索引是这样计算的:

index = x + y * width


此外,颜色通道存储在int的不同位中,不能简单地对整个int进行计算,因为这会使通道影响其他通道。

以下解决方案应该有效(即使只是使边界处的像素透明):

public static BufferedImage blur(BufferedImage image, int[] filter, int filterWidth) {
    if (filter.length % filterWidth != 0) {
        throw new IllegalArgumentException("filter contains a incomplete row");
    }

    final int width = image.getWidth();
    final int height = image.getHeight();
    final int sum = IntStream.of(filter).sum();

    int[] input = image.getRGB(0, 0, width, height, null, 0, width);

    int[] output = new int[input.length];

    final int pixelIndexOffset = width - filterWidth;
    final int centerOffsetX = filterWidth / 2;
    final int centerOffsetY = filter.length / filterWidth / 2;

    // apply filter
    for (int h = height - filter.length / filterWidth + 1, w = width - filterWidth + 1, y = 0; y < h; y++) {
        for (int x = 0; x < w; x++) {
            int r = 0;
            int g = 0;
            int b = 0;
            for (int filterIndex = 0, pixelIndex = y * width + x;
                    filterIndex < filter.length;
                    pixelIndex += pixelIndexOffset) {
                for (int fx = 0; fx < filterWidth; fx++, pixelIndex++, filterIndex++) {
                    int col = input[pixelIndex];
                    int factor = filter[filterIndex];

                    // sum up color channels seperately
                    r += ((col >>> 16) & 0xFF) * factor;
                    g += ((col >>> 8) & 0xFF) * factor;
                    b += (col & 0xFF) * factor;
                }
            }
            r /= sum;
            g /= sum;
            b /= sum;
            // combine channels with full opacity
            output[x + centerOffsetX + (y + centerOffsetY) * width] = (r << 16) | (g << 8) | b | 0xFF000000;
        }
    }

    BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    result.setRGB(0, 0, width, height, output, 0, width);
    return result;
}




int[] filter = {1, 2, 1, 2, 4, 2, 1, 2, 1};
int filterWidth = 3;
BufferedImage blurred = blur(img, filter, filterWidth);

07-25 23:23