Java:高斯模糊的实现

时间:2016-09-25 08:23:48

标签: java gaussianblur

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

  1. 我有一个矩阵(M)3x3(中间值是M(0,0)):

    1 2 1  
    2 4 2  
    1 2 1  
    
  2. 我从图像和每个最近的像素中取一个像素(P):

    s = M(-1, -1) * P(-1, -1) + M(-1, 0) * P(-1, 0) + ... + M(1, 1) * P(1, 1)  
    
  3. 然后划分矩阵的总值:

    P'(i, j) = s / M(-1, -1) + M(-1, 0) + ... + M(1, 1)
    
  4. 这就是我的计划所做的一切。我留下极端像素没有改变。

    我的节目:

    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);
    

    所以对于这个图像: Picture before

    结果如下: Picture after

    你能形容我吗,我的节目有什么问题?

1 个答案:

答案 0 :(得分:1)

首先,您在源数组中计算索引的公式是错误的。图像数据一个像素地排在另一个像素行中。因此,给定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);