Java: implementation of Gaussian Blur

帅比萌擦擦* 提交于 2021-01-28 22:15:42

问题


I need to implement Gaussian Blur in Java for 3x3, 5x5 and 7x7 matrix. Can you correct me if I'm wrong:

  1. I've a matrix(M) 3x3 (middle value is M(0, 0)):

    1 2 1  
    2 4 2  
    1 2 1  
    
  2. I take one pixel(P) from image and for each nearest pixel:

    s = M(-1, -1) * P(-1, -1) + M(-1, 0) * P(-1, 0) + ... + M(1, 1) * P(1, 1)  
    
  3. An then division it total value of matrix:

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

That's all that my program do. I leave extreme pixels not changed.

My program:

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];  
    }  
}

I get source from a BufferedImage like this:

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

So for this image:

Result is this:

Can you describe me, what is wrong with my program?


回答1:


First of all, your formula for calculating the index in the source array is wrong. The image data is stored in the array one pixel row after the other. Therefore the index given x and y is calculated like this:

index = x + y * width

Furthermore the color channels are stored in different bits of the int cannot simply do the calculations with the whole int, since this allows channels to influence other channels.

The following solution should work (even though it just leaves the pixels at the bounds transparent):

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


来源:https://stackoverflow.com/questions/39684820/java-implementation-of-gaussian-blur

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!