java - एंड्रॉइड एसडीके के लिए फास्ट बिटमैप ब्लर




android image-processing (12)

वर्तमान में एक एंड्रॉइड एप्लिकेशन में जो मैं विकसित कर रहा हूं, मैं इसे धुंधला करने के लिए किसी छवि के पिक्सल के माध्यम से लूपिंग कर रहा हूं। इसमें 640x480 छवि पर लगभग 30 सेकंड लगते हैं।

एंड्रॉइड मार्केट में ऐप ब्राउज़ करने के दौरान मैं एक ब्लर फीचर भी शामिल करता था और उनका धुंध बहुत तेज़ होता है (5 सेकेंड की तरह) ताकि वे धुंधली होने की एक अलग विधि का उपयोग कर रहे हों।

किसी को भी पिक्सेल के माध्यम से लूपिंग के अलावा एक तेज तरीका पता है?


एंड्रॉइड ब्लर गाइड 2016

गिथब पर शोकेस / बेंचमार्क ऐप और स्रोत के साथब्लर फ्रेमवर्क भी देखें जो मैं वर्तमान में काम कर रहा हूं: Dali

बहुत प्रयोग करने के बाद मैं अब आपको कुछ ठोस सिफारिशें सुरक्षित कर सकता हूं जो एंड्रॉइड फ्रेमवर्क का उपयोग करते समय एंड्रॉइड में आपके जीवन को आसान बना देगा।

लोड और डाउनस्केल्ड बिटमैप का उपयोग करें (बहुत धुंधली छवियों के लिए)

बिटमैप के पूर्ण आकार का कभी भी उपयोग न करें। जितनी अधिक छवि को धुंधला करने की आवश्यकता होती है और धुंध त्रिज्या जितनी अधिक होनी चाहिए और आम तौर पर ब्लर त्रिज्या जितना धीमा एल्गोरिदम होता है।

final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap blurTemplate = BitmapFactory.decodeResource(getResources(), R.drawable.myImage, options);

यह बिटमैप को नमूना आकार 8 के साथ लोड करेगा, इसलिए मूल छवि का केवल 1/64 होगा। परीक्षण करें कि नमूना आकार आपकी आवश्यकताओं के अनुरूप है, लेकिन स्केलिंग के कारण खराब गुणवत्ता से बचने के लिए इसे 2 ^ एन (2,4,8, ...) रखें। अधिक के लिए Google दस्तावेज़ देखें

एक और वास्तव में बड़ा फायदा यह है कि बिटमैप लोडिंग वास्तव में तेज़ होगा। मेरे शुरुआती धुंध परीक्षणों में मैंने पाया कि पूरे धुंध प्रक्रिया के दौरान सबसे लंबा समय छवि लोडिंग था। तो डिस्क से 1920x1080 छवि को लोड करने के लिए मेरे नेक्सस 5 को 500ms की आवश्यकता थी जबकि धुंधला केवल 250 एमएस या उससे अधिक ले लिया।

रेंडरस्क्रिप्ट का प्रयोग करें

ScriptIntrinsicBlur प्रदान करता है जो एक गॉसियन ब्लर फ़िल्टर है। इसमें अच्छी दृश्य गुणवत्ता है और यह वास्तव में सबसे तेज़ है जो आप वास्तव में एंड्रॉइड पर प्राप्त करते हैं। Google "मल्टीथ्रेड सी कार्यान्वयन से आमतौर पर 2-3x तेज और जावा कार्यान्वयन से 10x + तेज" होने का दावा करता है। रेंडरस्क्रिप्ट वास्तव में परिष्कृत है (फास्ट प्रोसेसिंग डिवाइस (जीपीयू, आईएसपी, आदि) आदि का उपयोग करके) और इसके लिए v8 समर्थन लाइब्रेरी भी है जो इसे 2.2 तक संगत बनाती है । कम से कम सिद्धांत में, मेरे स्वयं के परीक्षणों और अन्य देवताओं की रिपोर्ट के माध्यम से ऐसा लगता है कि रेन्डरस्क्रिप्ट का अंधाधुंध उपयोग करना संभव नहीं है, क्योंकि हार्डवेयर / ड्राइवर विखंडन कुछ उपकरणों के साथ समस्याएं पैदा करता है, यहां तक ​​कि उच्च sdk lvl (उदाहरण के लिए मेरे पास था) 4.1 नेक्सस एस के साथ परेशानी) तो सावधान रहें और बहुत से उपकरणों पर परीक्षण करें। यहां एक साधारण उदाहरण है जो आपको शुरू करेगा

//define this only once if blurring multiple times
RenderScript rs = RenderScript.create(context);

(...)
//this will blur the bitmapOriginal with a radius of 8 and save it in bitmapOriginal
final Allocation input = Allocation.createFromBitmap(rs, bitmapOriginal); //use this constructor for best performance, because it uses USAGE_SHARED mode which reuses memory
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setRadius(8f);
script.setInput(input);
script.forEach(output);
output.copyTo(bitmapOriginal);

ग्रैडल के साथ v8 समर्थन का उपयोग करते समय, जिसे विशेष रूप से Google द्वारा अनुशंसित किया जाता है "क्योंकि उनमें नवीनतम सुधार शामिल हैं" , आपको केवल अपनी बिल्ड स्क्रिप्ट में 2 लाइनें जोड़ने की आवश्यकता है और वर्तमान निर्माण टूल के साथ android.support.v8.renderscript उपयोग करें ( अद्यतन वाक्यविन्यास एंड्रॉइड ग्रेडल प्लगइन v14 + के लिए )

android {
    ...
    defaultConfig {
        ...
        renderscriptTargetApi 19
        renderscriptSupportModeEnabled true
    }
}

नेक्सस 5 पर सरल बेंचमार्क - विभिन्न अन्य जावा और रेंडरस्क्रिप्ट कार्यान्वयन के साथ रेंडरस्क्रिप्ट की तुलना करना:

विभिन्न तस्वीर आकारों पर औसत रनटाइम प्रति धुंध

प्रति सेकंड मेगापिक्सेल जो धुंधला हो सकता है

प्रत्येक मान 250 राउंड का औसत है। RS_GAUSS_FAST ScriptIntrinsicBlur (और लगभग हमेशा सबसे तेज़) है, ScriptIntrinsicBlur साथ शुरू होने वाले अन्य लोग सरल कर्नेल के साथ अधिकतर कार्यान्वयन को नियंत्रित करते हैं। एल्गोरिदम का विवरण यहां पाया जा सकता है । यह पूरी तरह धुंधला नहीं है, लेकिन एक अच्छा हिस्सा कचरा संग्रह है जिसे मापा जाता है। इसे यहां देखा जा सकता है (लगभग 500 राउंड के साथ 100x100 छवि पर ScriptIntrinsicBlur )

स्पाइक्स जीसी हैं।

आप स्वयं को देख सकते हैं, बेंचमार्क ऐप प्लेस्टोर में है : ब्लरबेन्मार्क

जहां भी संभव हो बिटमैप का पुन: उपयोग करता है (यदि प्राइयो: प्रदर्शन> मेमोरी पदचिह्न)

यदि आपको लाइव ब्लर या इसी तरह के लिए एकाधिक ब्लर्स की आवश्यकता है और आपकी मेमोरी इसे कई बार ड्रैबल्स से बिटमैप लोड नहीं करती है, लेकिन इसे सदस्य चर में "कैश" रखें। इस मामले में कचरा इकट्ठा करने के लिए हमेशा एक ही चर का उपयोग करने का प्रयास करें।

फ़ाइल या ड्रॉइंग से लोड करते समय नया "इन बिटमैप" विकल्प भी देखें, जो बिटमैप मेमोरी का पुन: उपयोग करेगा और कचरा संग्रहण समय बचाएगा

तेज से धुंध से मिश्रण के लिए

सरल और निष्पक्ष विधि सिर्फ 2 छविदृश्यों का उपयोग करने के लिए है, एक धुंधला और अल्फा उन्हें फीका करता है। लेकिन यदि आप एक अधिक परिष्कृत रूप चाहते हैं जो आसानी से तेज से धुंध से फीका हो, तो रोमन नूरिक के पोस्ट को उसके मुज़ी ऐप में कैसा करना है, इस बारे में जांचें।

असल में वह बताते हैं कि वह अलग-अलग धुंध के साथ कुछ फ्रेम को पूर्व-धुंधला करता है और उन्हें एनीमेशन में कीफ्रेम के रूप में उपयोग करता है जो वास्तव में चिकनी दिखता है


अब आप जल्दी से धुंधला करने के लिए रेंडरस्क्रिप्ट लाइब्रेरी से ScriptIntrinsicBlur उपयोग कर सकते हैं। यहां रेंडरस्क्रिप्ट एपीआई तक पहुंचने का तरीका बताया गया है। निम्नलिखित एक वर्ग है जिसे मैंने धुंधला और बिटमैप्स को धुंधला करने के लिए बनाया है:

public class BlurBuilder {
    private static final float BITMAP_SCALE = 0.4f;
    private static final float BLUR_RADIUS = 7.5f;

    public static Bitmap blur(View v) {
        return blur(v.getContext(), getScreenshot(v));
    }

    public static Bitmap blur(Context ctx, Bitmap image) {
        int width = Math.round(image.getWidth() * BITMAP_SCALE);
        int height = Math.round(image.getHeight() * BITMAP_SCALE);

        Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
        Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);

        RenderScript rs = RenderScript.create(ctx);
        ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
        Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
        Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
        theIntrinsic.setRadius(BLUR_RADIUS);
        theIntrinsic.setInput(tmpIn);
        theIntrinsic.forEach(tmpOut);
        tmpOut.copyTo(outputBitmap);

        return outputBitmap;
    }

    private static Bitmap getScreenshot(View v) {
        Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(b);
        v.draw(c);
        return b;
    }
}

भविष्य के Googlers के लिए, यहां एक एल्गोरिदम है जिसे मैंने Quasimondo से पोर्ट किया था। यह एक बॉक्स धुंध और एक गाऊशियन धुंध के बीच एक मिश्रण है, यह बहुत सुंदर और काफी तेज़ है:

/**
 * 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 <[email protected]>
 */

public Bitmap fastblur(Bitmap sentBitmap, float scale, int radius) {

    int width = Math.round(sentBitmap.getWidth() * scale);
    int height = Math.round(sentBitmap.getHeight() * scale);
    sentBitmap = Bitmap.createScaledBitmap(sentBitmap, width, height, false);

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

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

    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    int[] pix = new int[w * h];
    Log.e("pix", w + " " + h + " " + pix.length);
    bitmap.getPixels(pix, 0, w, 0, 0, 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;

    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;
    }
    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++) {
            // Preserve alpha channel: ( 0xff000000 & pix[yi] )
            pix[yi] = ( 0xff000000 & pix[yi] ) | ( 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;
        }
    }

    Log.e("pix", w + " " + h + " " + pix.length);
    bitmap.setPixels(pix, 0, w, 0, 0, w, h);

    return (bitmap);
}

मैंने पहले इसका इस्तेमाल किया ..

public static Bitmap myblur(Bitmap image, Context context) {
            final float BITMAP_SCALE = 0.4f;
            final float BLUR_RADIUS = 7.5f;
            int width = Math.round(image.getWidth() * BITMAP_SCALE);
            int height = Math.round(image.getHeight() * BITMAP_SCALE);
            Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
            Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
            RenderScript rs = RenderScript.create(context);
            ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
            Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
            Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
            theIntrinsic.setRadius(BLUR_RADIUS);
            theIntrinsic.setInput(tmpIn);
            theIntrinsic.forEach(tmpOut);
            tmpOut.copyTo(outputBitmap);
            return outputBitmap;
        }

यह मेरे लिए ठीक काम करता है: एंड्रॉइड के रेंडरस्क्रिप्ट के साथ छवियों को कुशलता से कैसे धुंधला करें

public class BlurBuilder {
    private static final float BITMAP_SCALE = 0.4f;
    private static final float BLUR_RADIUS = 7.5f;

    @SuppressLint("NewApi")
    public static Bitmap blur(Context context, Bitmap image) {
        int width = Math.round(image.getWidth() * BITMAP_SCALE);
        int height = Math.round(image.getHeight() * BITMAP_SCALE);

        Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height,
            false);
        Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);

        RenderScript rs = RenderScript.create(context);
        ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs,
            Element.U8_4(rs));
        Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
        Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
        theIntrinsic.setRadius(BLUR_RADIUS);
        theIntrinsic.setInput(tmpIn);
        theIntrinsic.forEach(tmpOut);
        tmpOut.copyTo(outputBitmap);

        return outputBitmap;
    }
}


For future Googlers who choose NDK approach - i find reliable mentioned stackblur algorithm. I found C++ implementation which does not rely on SSE here - http://www.antigrain.com/__code/include/agg_blur.h.html#stack_blur_rgba32 which contains some optimizations using static tables like:

static unsigned short const stackblur_mul[255] =
{
    512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,
    454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,
    482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,
    437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,
    497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,
    320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,
    446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,
    329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,
    505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,
    399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,
    324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,
    268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,
    451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,
    385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,
    332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,
    289,287,285,282,280,278,275,273,271,269,267,265,263,261,259
};

static unsigned char const stackblur_shr[255] =
{
    9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
    17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
    20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
    23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
}; 

I made modification of stackblur algorithm for multi-core systems - it can be found here http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/ As more and more devices have 4 cores - optimizations give 4x speed benefit.



This is for all people who need to increase the radius of ScriptIntrinsicBlur to obtain a harder gaussian blur.

Instead of to put the radius more than 25, you can scale down the image and get the same result. I wrote a class called GaussianBlur . Below you can see how to use, and the whole class implementation.

उपयोग:

GaussianBlur gaussian = new GaussianBlur(context);
gaussian.setMaxImageSize(60);
gaussian.setRadius(25); //max

Bitmap output = gaussian.render(<your bitmap>,true);
Drawable d = new BitmapDrawable(getResources(),output);

वर्ग:

 public class GaussianBlur {
    private final int DEFAULT_RADIUS = 25;
    private final float DEFAULT_MAX_IMAGE_SIZE = 400;

    private Context context;
    private int radius;
    private float maxImageSize;

    public GaussianBlur(Context context) {
    this.context = context;
    setRadius(DEFAULT_RADIUS);
    setMaxImageSize(DEFAULT_MAX_IMAGE_SIZE);
    } 

    public Bitmap render(Bitmap bitmap, boolean scaleDown) {
    RenderScript rs = RenderScript.create(context);

    if (scaleDown) {
        bitmap = scaleDown(bitmap);
    }

    Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);

    Allocation inAlloc = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_GRAPHICS_TEXTURE);
    Allocation outAlloc = Allocation.createFromBitmap(rs, output);

    ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, inAlloc.getElement()); // Element.U8_4(rs));
    script.setRadius(getRadius());
    script.setInput(inAlloc);
    script.forEach(outAlloc);
    outAlloc.copyTo(output);

    rs.destroy();

    return output;
}

public Bitmap scaleDown(Bitmap input) {
    float ratio = Math.min((float) getMaxImageSize() / input.getWidth(), (float) getMaxImageSize() / input.getHeight());
    int width = Math.round((float) ratio * input.getWidth());
    int height = Math.round((float) ratio * input.getHeight());

    return Bitmap.createScaledBitmap(input, width, height, true);
}

public int getRadius() {
    return radius;
}

public void setRadius(int radius) {
    this.radius = radius;
}

public float getMaxImageSize() {
    return maxImageSize;
}

public void setMaxImageSize(float maxImageSize) {
    this.maxImageSize = maxImageSize;
}
    }

We tried to implement RenderScript blur like mentioned above in different answers. We were limited to use the v8 RenderScript version and that caused us a lot of trouble.

  • Samsung S3 crashed randomly whenever we tried to use the renderscript
  • Other devices (across different APIs) randomly showed different color issues

I want to share our dirty Java-only version which is slow and should be done on a separate thread and, if possible, before usage and therefore persisted.

private final Paint mPaint = new Paint();

public Bitmap blur(final String pathToBitmap) {
    final BitmapFactory.Options options = new BitmapFactory.Options();
    final Bitmap normalOne = BitmapFactory.decodeFile(pathToBitmap, options);
    final Bitmap resultBitmap = Bitmap.createBitmap(options.outWidth, options.outHeight, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(resultBitmap);
    mPaint.setAlpha(180);
    canvas.drawBitmap(normalOne, 0, 0, mPaint);
    int blurRadius = 12;
    for (int row = -blurRadius; row < blurRadius; row += 2) {
        for (int col = -blurRadius; col < blurRadius; col += 2) {
            if (col * col + row * row <= blurRadius * blurRadius) {
                mPaint.setAlpha((blurRadius * blurRadius) / ((col * col + row * row) + 1) * 2);
                canvas.drawBitmap(normalOne, row, col, mPaint);
            }
        }
    }
    normalOne.recycle();
    return resultBitmap;
}

This solution is far from perfect but creates a reasonable blur effect based on the fact, that it draws highly transparent version of the same image on top of a barely transparent "sharp" version. The alpha depends on the distance to the origin.

You can adjust some "magic numbers" to your needs. I just wanted to share that "solution" for everybody who has issues with the v8 support version of RenderScript.


यह अंधेरे में एक शॉट है, लेकिन आप छवि को कम करने की कोशिश कर सकते हैं और फिर इसे फिर से बढ़ा सकते हैं। यह Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) साथ किया जा सकता है। सुनिश्चित करें और फ़िल्टर पैरामीटर को सही पर सेट करें। यह देशी कोड में चलाएगा ताकि यह तेज़ हो सके।


यहां रेंडरस्क्रिप्ट का उपयोग करके एक रीयलटाइम धुंधला ओवरले है, जो कि पर्याप्त तेज़ लगता है।

https://github.com/mmin18/RealtimeBlurView







renderscript