1

3x3、5x5、および 7x7 マトリックス用に Java で Gaussian Blur を実装する必要があります。間違っていたら訂正してもらえますか:

  1. 私はマトリックス(M)3x3を持っています(中間値はM(0、0)です):

    1 2 1  
    2 4 2  
    1 2 1  
    
  2. 画像から 1 つのピクセル (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)
    

私のプログラムが行うことはそれだけです。極端なピクセルは変更せずに残します。

私のプログラム:

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

したがって、この画像の場合: 前の写真

結果は次のとおりです。 後の写真

私のプログラムの何が問題なのか説明してもらえますか?

4

1 に答える 1

1

まず、ソース配列のインデックスを計算する式が間違っています。画像データは、アレイ内のピクセル行ごとに格納されます。xしたがって、指定されたインデックスyは次のように計算されます。

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);
于 2016-09-25T11:57:26.133 に答える