|  | 
|  | 1 | +package com.mobge.simpleimageprocessing; | 
|  | 2 | + | 
|  | 3 | + | 
|  | 4 | +public class BoxBlurFilter extends BaseBufferedFilter { | 
|  | 5 | + | 
|  | 6 | + | 
|  | 7 | +    private Configuration _configuration; | 
|  | 8 | + | 
|  | 9 | +    private ImageData _dataBuffer2; | 
|  | 10 | + | 
|  | 11 | +    public BoxBlurFilter(int width, int height) { | 
|  | 12 | +        super(width, height); | 
|  | 13 | +        _dataBuffer2 = new ImageData(width, height); | 
|  | 14 | +    } | 
|  | 15 | +    public BoxBlurFilter setConfiguration(Configuration configuration){ | 
|  | 16 | +        _configuration = configuration; | 
|  | 17 | +        return this; | 
|  | 18 | +    } | 
|  | 19 | + | 
|  | 20 | +    @Override | 
|  | 21 | +    public void performOperation() { | 
|  | 22 | +        ImageData image = getInput(0); | 
|  | 23 | +        assertSize(image); | 
|  | 24 | +        _dataBuffer.copyFrom(image); | 
|  | 25 | +        for(int i = 0; i < _configuration.repeat; i++){ | 
|  | 26 | +            blur(); | 
|  | 27 | +        } | 
|  | 28 | + | 
|  | 29 | +        copyRedToGreenBlue(); | 
|  | 30 | +        sendOutput(_dataBuffer, 0); | 
|  | 31 | +    } | 
|  | 32 | + | 
|  | 33 | +    private void swapBuffers() { | 
|  | 34 | +        ImageData temp = _dataBuffer2; | 
|  | 35 | +        _dataBuffer2 = _dataBuffer; | 
|  | 36 | +        _dataBuffer = temp; | 
|  | 37 | +    } | 
|  | 38 | + | 
|  | 39 | +    private void blur() { | 
|  | 40 | +        int w = _dataBuffer.getWidth(); | 
|  | 41 | +        int h = _dataBuffer.getHeight(); | 
|  | 42 | +        int r = _configuration.radius; | 
|  | 43 | +        accumH(w, h, r); | 
|  | 44 | +        accumV(w, h, r); | 
|  | 45 | +    } | 
|  | 46 | +    private void accumV(int w, int h, int r) { | 
|  | 47 | +        final int bbp = ImageData.BYTES_PER_PIXEL; | 
|  | 48 | +        final int stride = w * bbp; | 
|  | 49 | +        accum(w, h, bbp, stride, r); | 
|  | 50 | +    } | 
|  | 51 | +    private void accumH(int w, int h, int r) { | 
|  | 52 | +        final int bbp = ImageData.BYTES_PER_PIXEL; | 
|  | 53 | +        final int stride = w * bbp; | 
|  | 54 | +        accum(h, w, stride, bbp, r); | 
|  | 55 | +    } | 
|  | 56 | +    private void accum(int rowCount, int columnCount, | 
|  | 57 | +                       int offStep, int indexStep, | 
|  | 58 | +                       int radius) { | 
|  | 59 | +        float[] source = _dataBuffer.getRawData(); | 
|  | 60 | +        float[] target = _dataBuffer2.getRawData(); | 
|  | 61 | +        final float normalizer = 1.0f / (radius + radius + 1); | 
|  | 62 | +        final int bR = radius * indexStep; | 
|  | 63 | +        final int stride = columnCount * indexStep; | 
|  | 64 | +        int endOffset = rowCount * offStep + ImageData.OFFSET_R; | 
|  | 65 | +        for (int offset = ImageData.OFFSET_R; offset < endOffset; offset += offStep) { | 
|  | 66 | +            float firstValue = source[offset]; | 
|  | 67 | +            // assume off screen values are the same with pixel on the edge | 
|  | 68 | +            // and predict accumulation value according to that | 
|  | 69 | +            float accumulation = firstValue * radius; | 
|  | 70 | +            int i = offset; | 
|  | 71 | +            int end = offset + bR; | 
|  | 72 | +            for (; i < end; i += indexStep) { | 
|  | 73 | +                accumulation += source[i]; | 
|  | 74 | +            } | 
|  | 75 | + | 
|  | 76 | +            // calculate blur for range x = 0 -> r | 
|  | 77 | +            i = offset; | 
|  | 78 | +            for (; i < end; i += indexStep) { | 
|  | 79 | +                accumulation += source[i + bR]; | 
|  | 80 | +                target[i] = accumulation * normalizer; | 
|  | 81 | +                accumulation -= firstValue; | 
|  | 82 | +            } | 
|  | 83 | + | 
|  | 84 | +            // calculate blur for range x = r -> (width - r) | 
|  | 85 | +            end = stride - bR + offset; | 
|  | 86 | +            for (; i < end; i += indexStep) { | 
|  | 87 | +                accumulation += source[i + bR]; | 
|  | 88 | +                target[i] = accumulation * normalizer; | 
|  | 89 | +                accumulation -= source[i - bR]; | 
|  | 90 | +            } | 
|  | 91 | + | 
|  | 92 | +            // calculate blur for range x = (width - r) -> width | 
|  | 93 | +            end = offset + stride; | 
|  | 94 | +            float lastValue = source[end - indexStep]; | 
|  | 95 | +            for (; i < end; i += indexStep) { | 
|  | 96 | +                accumulation += lastValue; | 
|  | 97 | +                target[i] = accumulation * normalizer; | 
|  | 98 | +                accumulation -= source[i - bR]; | 
|  | 99 | +            } | 
|  | 100 | +        } | 
|  | 101 | +        swapBuffers(); | 
|  | 102 | +    } | 
|  | 103 | + | 
|  | 104 | + | 
|  | 105 | +    public static class Configuration { | 
|  | 106 | +        int radius; | 
|  | 107 | +        int repeat; | 
|  | 108 | + | 
|  | 109 | +        /** | 
|  | 110 | +         * Creates a configuration object to perform a box blur. | 
|  | 111 | +         * @param radius a radius for box blur operation. One dimension of box is | 
|  | 112 | +         *               calculated as (2 * radius + 1). | 
|  | 113 | +         * @param repeat repeat count that box blur operation will be performed. | 
|  | 114 | +         *               Multiple passes of the box blur approximates to gaussian blur. | 
|  | 115 | +         */ | 
|  | 116 | +        public Configuration(int radius, int repeat){ | 
|  | 117 | +            this.radius = radius; | 
|  | 118 | +            this.repeat = repeat; | 
|  | 119 | +        } | 
|  | 120 | +    } | 
|  | 121 | +} | 
0 commit comments