0

最近,我尝试了blur一个图像,半径是可变的。我试图实现它 myseft,但它似乎很慢。从这个站点,我得到了一个快速模糊方法,称为stack blur

  static Bitmap fastblur(Bitmap sentBitmap, int radius, int fromX, int fromY,
        int width, int height) {

    // Stack Blur v1.0 from
    // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
    //
    // Java Author: Mario Klingemann <mario at quasimondo.com>
    // http://incubator.quasimondo.com
    // created Feburary 29, 2004
    // Android port : Yahel Bouaziz <yahel at kayenko.com>
    // http://www.kayenko.com
    // ported april 5th, 2012

    // This is a compromise between Gaussian Blur and Box blur
    // It creates much better looking blurs than Box Blur, but is
    // 7x faster than my Gaussian Blur implementation.
    //
    // I called it Stack Blur because this describes best how this
    // filter works internally: it creates a kind of moving stack
    // of colors whilst scanning through the image. Thereby it
    // just has to add one new block of color to the right side
    // of the stack and remove the leftmost color. The remaining
    // colors on the topmost layer of the stack are either added on
    // or reduced by one, depending on if they are on the right or
    // on the left side of the stack.
    //
    // If you are using this algorithm in your code please add
    // the following line:
    //
    // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>

    Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);

    if (radius < 1) {
        return (null);
    }

    int w = width;
    int h = height;

    int[] pix = new int[w * h];

    bitmap.getPixels(pix, 0, w, fromX, fromY, w, h);

    int wm = w - 1;
    int hm = h - 1;
    int wh = w * h;
    int div = radius + radius + 1;

    int r[] = new int[wh];
    int g[] = new int[wh];
    int b[] = new int[wh];
    int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
    int vmin[] = new int[Math.max(w, h)];

    int divsum = (div + 1) >> 1;
    divsum *= divsum;
    int dv[] = new int[256 * divsum];
    for (i = 0; i < 256 * divsum; i++) {
        dv[i] = (i / divsum);
    }

    yw = yi = 0;

    int[][] stack = new int[div][3];
    int stackpointer;
    int stackstart;
    int[] sir;
    int rbs;
    int r1 = radius + 1;
    int routsum, goutsum, boutsum;
    int rinsum, ginsum, binsum;

    int originRadius = radius;
    for (y = 0; y < h; y++) {
        rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
        for (i = -radius; i <= radius; i++) {
            p = pix[yi + Math.min(wm, Math.max(i, 0))];
            sir = stack[i + radius];
            sir[0] = (p & 0xff0000) >> 16;
            sir[1] = (p & 0x00ff00) >> 8;
            sir[2] = (p & 0x0000ff);
            rbs = r1 - Math.abs(i);
            rsum += sir[0] * rbs;
            gsum += sir[1] * rbs;
            bsum += sir[2] * rbs;
            if (i > 0) {
                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];
            } else {
                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];
            }
        }
        stackpointer = radius;

        for (x = 0; x < w; x++) {

            r[yi] = dv[rsum];
            g[yi] = dv[gsum];
            b[yi] = dv[bsum];

            rsum -= routsum;
            gsum -= goutsum;
            bsum -= boutsum;

            stackstart = stackpointer - radius + div;
            sir = stack[stackstart % div];

            routsum -= sir[0];
            goutsum -= sir[1];
            boutsum -= sir[2];

            if (y == 0) {
                vmin[x] = Math.min(x + radius + 1, wm);
            }
            p = pix[yw + vmin[x]];

            sir[0] = (p & 0xff0000) >> 16;
            sir[1] = (p & 0x00ff00) >> 8;
            sir[2] = (p & 0x0000ff);

            rinsum += sir[0];
            ginsum += sir[1];
            binsum += sir[2];

            rsum += rinsum;
            gsum += ginsum;
            bsum += binsum;

            stackpointer = (stackpointer + 1) % div;
            sir = stack[(stackpointer) % div];

            routsum += sir[0];
            goutsum += sir[1];
            boutsum += sir[2];

            rinsum -= sir[0];
            ginsum -= sir[1];
            binsum -= sir[2];

            yi++;
        }
        yw += w;
    }

    radius = originRadius;

    for (x = 0; x < w; x++) {
        rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
        yp = -radius * w;
        for (i = -radius; i <= radius; i++) {
            yi = Math.max(0, yp) + x;

            sir = stack[i + radius];

            sir[0] = r[yi];
            sir[1] = g[yi];
            sir[2] = b[yi];

            rbs = r1 - Math.abs(i);

            rsum += r[yi] * rbs;
            gsum += g[yi] * rbs;
            bsum += b[yi] * rbs;

            if (i > 0) {
                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];
            } else {
                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];
            }

            if (i < hm) {
                yp += w;
            }
        }
        yi = x;
        stackpointer = radius;
        for (y = 0; y < h; y++) {
            pix[yi] = 0xff000000 | (dv[rsum] << 16) | (dv[gsum] << 8)
                    | dv[bsum];

            rsum -= routsum;
            gsum -= goutsum;
            bsum -= boutsum;

            stackstart = stackpointer - radius + div;
            sir = stack[stackstart % div];

            routsum -= sir[0];
            goutsum -= sir[1];
            boutsum -= sir[2];

            if (x == 0) {
                vmin[y] = Math.min(y + r1, hm) * w;
            }
            p = x + vmin[y];

            sir[0] = r[p];
            sir[1] = g[p];
            sir[2] = b[p];

            rinsum += sir[0];
            ginsum += sir[1];
            binsum += sir[2];

            rsum += rinsum;
            gsum += ginsum;
            bsum += binsum;

            stackpointer = (stackpointer + 1) % div;
            sir = stack[stackpointer];

            routsum += sir[0];
            goutsum += sir[1];
            boutsum += sir[2];

            rinsum -= sir[0];
            ginsum -= sir[1];
            binsum -= sir[2];

            yi += w;
        }
    }

    bitmap.setPixels(pix, 0, w, fromX, fromY, w, h);

    return (bitmap);
}

实际上,我希望这种模糊方法可以是可变模糊(例如:当到图像中心的距离减小时,半径也减小)。但是,我不擅长移位,修改那些代码对我来说太难了!所以,我想寻求一种方法来实现像径向模糊这样的代码!我想知道在android中有没有包含径向模糊、灰度、....的模糊库!如果有人能帮助我,真的很感激!谢谢!

4

2 回答 2

4

Due to its optimization for speed, this algorithm is not well suited to be adapted for a varying radius. You can still use it if you take a different approach:

The principle is that you create multiple temporary maps each with an increasing (uniform) blur radius and then blend two of them together based on how big the radius at that point should be. Let's say you prepare 3 temp maps, one with radius 4, one with 8 and one with 16. Now you want a blur radius of 12 at one pixel. What you do is you blend map 2 and 3 with about 50%. The more temp maps you use the better the quality, but 3 (plus the original unblurred map) are usually sufficient.

I am using this technique in my Compound Blur for Canvas: http://www.quasimondo.com/CompoundBlurForCanvas/CompoundBlurDemo.html - this allows you to do tilt shift effects or vignettes.

If you are looking for a radial blur that looks more like a camera zoom effect you have to use a different approach. In that case you first transform the bitmap from cartesian mapping to polar mapping, then you do a horizontal blur and finally you transform the map back to cartesian space - there is a Flash demo and some source code on my site, also a more detailed explanation: http://www.quasimondo.com/archives/000697.php

于 2012-08-31T00:59:53.153 回答
0

How to implement a compound blur with a slider:

///HTML///

//Use: CompoundBlur.js//

<DIV CLASS="specimenWindow">

    <DIV CLASS="specimenImage">

        <IMG ID="specImg" WIDTH="150" HEIGHT="150" />
        <CANVAS ID="specCanvas" WIDTH="150" HEIGHT="150"></CANVAS>

    </DIV>

</DIV>

<SCRIPT TYPE="text/javascript" SRC="js/CompoundBlur.js"></SCRIPT>

///CSS///

.specimenWindow {
    position: absolute;
    width: 150px;
    height: 150px;
    left: 37px;
    top: 96px;
}

.specimenImage {
    height: 150px;
    width: 150px;
}

#specCanvas {
    position: absolute;
    top: 27px;
    left: 2px;
}

///JS///

var specImg = document.getElementById("specImg");

_slider.ontouchend = function() {
    compoundBlur();
} 

function compoundBlur() {
    var lensRead = _slider.getPosition(0, 80);
    var rData = getRadialGradientMap( 150, 150, 75, 75, 25, 60 ); 
    compoundBlurImage( "specImg", "specCanvas", rData, lensRead, 1.5, 2, true );
}

So, just adjust the values to get smoother blur effects, I have it blurring when my slider is finished being touched, this is way more efficient on mobile devices vs. constantly blurring when slider changes, otherwise iPad will get warm and start loosing battery power quickly

And so hope that helps anyone trying to implement a fast compound blur.

于 2014-03-31T20:08:10.373 回答