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


185

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

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

किसी को भी पिक्सेल के माध्यम से पाशन के अलावा एक तेज़ तरीका पता है?


2
दुर्भाग्य से चित्र हमेशा अलग होंगे इसलिए मैं समय से पहले धुंधला संस्करण नहीं बना पाऊंगा। इसके अलावा, मैं या तो समय से पहले धुंधला तीव्रता पता नहीं होगा।
ग्रेग

क्या आप अपना कोड पोस्ट कर सकते हैं, हो सकता है कि यह एल्गोरिथ्म / कोड है जो अक्षम है, एक 640x480 छवि के माध्यम से जाने के लिए 30 सेकंड धीमा है, मैंने सोचा होगा कि 5 सेकंड धीमा था, लेकिन फिर प्रोसेसर पर निर्भर करता है।
विक्रिक

जवाबों:


78

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


5
कुछ परीक्षण और धुंधलेपन के बाद कि मैं यह वास्तविक काम कर रहा हूं, मेरे लिए काफी अच्छा है और यह तेज है। धन्यवाद!
ग्रेग

4
अगर यह अच्छा काम करता है। यह शर्म की बात है कि हम कभी इस बात की तह तक नहीं गए कि यह अक्षम क्यों था।
विक्रिक

आप createScaledBitmap को आज़माना चाहते हैं और छवि को उसी आकार में छोड़ सकते हैं। यह मेरे लिए इसे धुंधला कर रहा है :-(
केसबश

1
यहाँ तर्क "फिल्टर" के अर्थ पर एक चर्चा है: stackoverflow.com/questions/2895065
user1364368

4
यह 2 कारणों से प्राप्त करने का बिल्कुल तरीका नहीं है: 1) यह पूरी छवि की स्मृति की आवश्यकता है पूरी तरह से आप शायद केवल एक नीचे 2 का उपयोग कर रहे हैं) आपको पूरी छवि लोड करने की आवश्यकता है जो धीमी है - इनसाइडाइज के साथ लोडिंग का उपयोग करें और BitmapFactory.decodeResource (), जो इससे बेहतर समाधान है।
पैट्रिक फेवरे

301

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

ArrayIndexOutOfBoundsException समस्या का सामना कर रहे लोगों के लिए अपडेट: @ टिप्पणी में @anthonycr इस प्रकार है:

मैंने पाया कि StrictMath.abs या कुछ अन्य अनुपस्थित कार्यान्वयन के साथ Math.abs की जगह लेने से दुर्घटना नहीं होती है।

/**
 * 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>
 */

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

4
धन्यवाद येल। आपने मेरी समस्या का समाधान कर दिया। एक बार फिर धन्यवाद।
योग गुरु १

1
मुझे त्रिज्या के रूप में क्या पास करना चाहिए?
krisDrOid

16
1 से बड़े त्रिज्या के लिए कभी-कभी आपको ArrayIndexOutOfBoundsException मिलती है। मैं समस्या की पहचान करने की कोशिश करूंगा।
14

7
@MichaelLiberman मैं भी एक ही समस्या का सामना किया। बाहर क्यों अभी तक? "जी [यी] = डीवी [जीसम];" -> त्रुटि: java.lang.ArrayIndexOutOfBoundsException: लंबाई = 112896; सूचकांक = ११४०२१
देखिए

2
ज्ञात ArrayIndexOutOfBoundsException में भाग गया, और कुछ विश्लेषण के बाद, मेरा मानना ​​है कि यह Dalvik VM द्वारा गलत अनुकूलन के कारण है। में forपाश तुरंत बुरा भिन्नता से पहले, या तो की गणना rbsचर या की गणना gsum, rsumया bsumचर किया सही नहीं किया जा रहा है। मैंने पाया कि की जगह Math.absके साथ StrictMath.absया कुछ अन्य absकार्यान्वयन, दुर्घटना नहीं होती है। चूँकि यह StrictMath.absखुद को दर्शाता है Math.abs, ऐसा लगता है कि यह एक बुरा अनुकूलन होना चाहिए।
एंथनीक्रॉस

255

Android Blur Guide 2016

Github पर शोकेस / बेंचमार्क ऐप और स्रोत के साथइसके अलावा मैं वर्तमान में काम कर रहा ब्लर फ्रेमवर्क की जाँच कर रहा हूँ: डाली

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

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

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

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

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

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

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

रेंडरस्क्रिप्ट वह प्रदान करता है ScriptIntrinsicBlurजो एक गाऊसी ब्लर फिल्टर है। इसमें अच्छी दृश्य गुणवत्ता है और यह केवल सबसे तेज़ है जो आप वास्तविक रूप से Android पर प्राप्त करते हैं। Google का दावा है कि "आमतौर पर मल्टीथ्रेड सी कार्यान्वयन से 2-3 गुना तेज और अक्सर जावा कार्यान्वयन से 10x + तेज" होता है । रेंडरस्क्रिप्ट वास्तव में परिष्कृत है (सबसे तेज़ प्रोसेसिंग डिवाइस (GPU, ISP, इत्यादि), आदि का उपयोग करके) और इसके लिए v8 सपोर्ट लाइब्रेरी भी है जो इसे 2.2 से नीचे संगत बनाता है। । अच्छी तरह से कम से कम सिद्धांत में, मेरे अपने परीक्षणों और अन्य देवों की रिपोर्टों के माध्यम से ऐसा लगता है कि रेंडरस्क्रिप्ट का उपयोग आँख बंद करके करना संभव नहीं है, क्योंकि हार्डवेयर / चालक विखंडन के कारण कुछ उपकरणों के साथ समस्याएँ पैदा होती हैं, यहां तक ​​कि उच्च एसडीके 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(और लगभग हमेशा सबसे तेजी से), दूसरों कि के साथ शुरू RS_ज्यादातर सरल कर्नेल के साथ convolve कार्यान्वयन हैं। एल्गोरिदम का विवरण यहां पाया जा सकता है । यह विशुद्ध रूप से धुंधला नहीं है, क्योंकि एक अच्छा हिस्सा कचरा संग्रह है जिसे मापा जाता है। इसे यहां देखा जा सकता है ( ScriptIntrinsicBlurलगभग 100 राउंड के साथ 100x100 चित्र पर)

यहां छवि विवरण दर्ज करें

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

आप अपने लिए जाँच सकते हैं, बेंचमार्क ऐप प्लेस्टोर में है : BlurBenchmark

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

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

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

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

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

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

आरेख जहाँ नुरिक अपने दृष्टिकोण को समाप्त करता है


1
सबसे पहले, आपकी कड़ी मेहनत के लिए धन्यवाद! लेकिन मुझे एक सवाल मिला: "क्योंकि यह USAGE_SHARED मोड का उपयोग करता है जो मेमोरी का पुन: उपयोग करता है"। आपको लगातार USAGE_SHARED कहां मिला? मुझे यह कहीं नहीं मिला।
कुछ नोब स्टूडेंट

2
मैंने पाया, USAGE_SHARED केवल support.v8.renderscript में उपलब्ध है
कुछ Noob छात्र

2
रेंडरस्क्रिप्ट तेजी से गाऊसी धब्बा कम अंत उपकरणों पर सी मेमोरी आवंटन त्रुटियों के साथ विफल हो जाता है। प्रदान किए गए Play Store ऐप का उपयोग करके ZTE Z992 (Android 4.1.1) और Kyocera उदय (Android 4.0.4) पर परीक्षण किया गया। इसके अलावा सैमसंग गैलेक्सी एस 3 मिनी पर एक विफलता रिपोर्ट थी। चूंकि सी परत में त्रुटियां होती हैं, उन्हें जावा में अपवाद के रूप में नहीं फँसाया जा सकता है, जिसका अर्थ है कि ऐप क्रैश अपरिहार्य है। ऐसा लगता है कि रेंडरस्क्रिप्ट उत्पादन उपयोग के लिए तैयार नहीं हो सकता है।
थियो

4
नए ग्रेड के संस्करणों के लिए, उपयोग करें renderscriptSupportModeEnabled trueया इसका निर्माण नहीं होगा! मैंने हमेशा के लिए खोज की!
seb


53

EDIT (अप्रैल 2014): यह एक प्रश्न / उत्तर पृष्ठ है जो अभी भी बहुत हिट लगता है। मुझे पता है कि मैं इस पद के लिए हमेशा तैयार रहा हूँ। लेकिन अगर आप इसे पढ़ रहे हैं, तो आपको यहां पोस्ट किए गए उत्तरों को महसूस करने की आवश्यकता है (मेरा और स्वीकृत उत्तर दोनों) पुराने हैं। यदि आप आज कुशल कलंक को लागू करना चाहते हैं , तो आपको एनडीके या जावा के बजाय रेंडरस्क्रिप्ट का उपयोग करना चाहिए । रेंडरस्क्रिप्ट Android 2.2+ ( Android समर्थन लाइब्रेरी का उपयोग करके) पर चलता है ) , इसलिए इसका उपयोग न करने का कोई कारण नहीं है।

पुराना उत्तर इस प्रकार है, लेकिन पुराने होने के नाते सावधान रहें।


भविष्य के गोगलर्स के लिए, यहां एक एल्गोरिथ्म है जिसे मैंने याहेल के पोर्ट क्वासिमोंडो के एल्गोरिथ्म से पोर्ट किया था, लेकिन एनडीके का उपयोग करके। यह येल के उत्तर पर आधारित है, निश्चित रूप से। लेकिन यह मूल सी कोड चल रहा है, इसलिए यह तेज है। काफी तेज। जैसे, ४० गुना तेज।

मुझे लगता है कि NDK का उपयोग करना Android पर सभी छवि हेरफेर कैसे किया जाना चाहिए ... यह पहली बार में लागू करने के लिए कुछ हद तक परेशान है ( यहां जेएनआई और एनडीके का उपयोग करने पर एक महान ट्यूटोरियल पढ़ें ), लेकिन बहुत बेहतर है, और वास्तविक समय के लिए निकट है बहुत सारी चीज़ें।

संदर्भ के लिए, याहेल के जावा फ़ंक्शन का उपयोग करते हुए, मेरी 480x532 पिक्सल छवि को धुंधला करने में 10 सेकंड का समय लगा। 10. के धुंधले त्रिज्या के साथ, लेकिन मूल सी संस्करण का उपयोग करते हुए यह 250ms का हो गया। और मुझे पूरा यकीन है कि इसे अभी भी और अनुकूलित किया जा सकता है ... मैंने सिर्फ जावा कोड का एक गूंगा रूपांतरण किया है, शायद कुछ जोड़तोड़ हैं जिन्हें छोटा किया जा सकता है, पूरी बात को फिर से तैयार करने में बहुत अधिक समय खर्च नहीं करना चाहते हैं।

#include <jni.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <android/log.h>
#include <android/bitmap.h>

#define LOG_TAG "libbitmaputils"
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

typedef struct {
    uint8_t red;
    uint8_t green;
    uint8_t blue;
    uint8_t alpha;
} rgba;

JNIEXPORT void JNICALL Java_com_insert_your_package_ClassName_functionToBlur(JNIEnv* env, jobject obj, jobject bitmapIn, jobject bitmapOut, jint radius) {
    LOGI("Blurring bitmap...");

    // Properties
    AndroidBitmapInfo   infoIn;
    void*               pixelsIn;
    AndroidBitmapInfo   infoOut;
    void*               pixelsOut;

    int ret;

    // Get image info
    if ((ret = AndroidBitmap_getInfo(env, bitmapIn, &infoIn)) < 0 || (ret = AndroidBitmap_getInfo(env, bitmapOut, &infoOut)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }

    // Check image
    if (infoIn.format != ANDROID_BITMAP_FORMAT_RGBA_8888 || infoOut.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        LOGE("Bitmap format is not RGBA_8888!");
        LOGE("==> %d %d", infoIn.format, infoOut.format);
        return;
    }

    // Lock all images
    if ((ret = AndroidBitmap_lockPixels(env, bitmapIn, &pixelsIn)) < 0 || (ret = AndroidBitmap_lockPixels(env, bitmapOut, &pixelsOut)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

    int h = infoIn.height;
    int w = infoIn.width;

    LOGI("Image size is: %i %i", w, h);

    rgba* input = (rgba*) pixelsIn;
    rgba* output = (rgba*) pixelsOut;

    int wm = w - 1;
    int hm = h - 1;
    int wh = w * h;
    int whMax = max(w, h);
    int div = radius + radius + 1;

    int r[wh];
    int g[wh];
    int b[wh];
    int rsum, gsum, bsum, x, y, i, yp, yi, yw;
    rgba p;
    int vmin[whMax];

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

    yw = yi = 0;

    int stack[div][3];
    int stackpointer;
    int stackstart;
    int rbs;
    int ir;
    int ip;
    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 = input[yi + min(wm, max(i, 0))];

            ir = i + radius; // same as sir

            stack[ir][0] = p.red;
            stack[ir][1] = p.green;
            stack[ir][2] = p.blue;
            rbs = r1 - abs(i);
            rsum += stack[ir][0] * rbs;
            gsum += stack[ir][1] * rbs;
            bsum += stack[ir][2] * rbs;
            if (i > 0) {
                rinsum += stack[ir][0];
                ginsum += stack[ir][1];
                binsum += stack[ir][2];
            } else {
                routsum += stack[ir][0];
                goutsum += stack[ir][1];
                boutsum += stack[ir][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;
            ir = stackstart % div; // same as sir

            routsum -= stack[ir][0];
            goutsum -= stack[ir][1];
            boutsum -= stack[ir][2];

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

            stack[ir][0] = p.red;
            stack[ir][1] = p.green;
            stack[ir][2] = p.blue;

            rinsum += stack[ir][0];
            ginsum += stack[ir][1];
            binsum += stack[ir][2];

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

            stackpointer = (stackpointer + 1) % div;
            ir = (stackpointer) % div; // same as sir

            routsum += stack[ir][0];
            goutsum += stack[ir][1];
            boutsum += stack[ir][2];

            rinsum -= stack[ir][0];
            ginsum -= stack[ir][1];
            binsum -= stack[ir][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 = max(0, yp) + x;

            ir = i + radius; // same as sir

            stack[ir][0] = r[yi];
            stack[ir][1] = g[yi];
            stack[ir][2] = b[yi];

            rbs = r1 - abs(i);

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

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

            if (i < hm) {
                yp += w;
            }
        }
        yi = x;
        stackpointer = radius;
        for (y = 0; y < h; y++) {
            output[yi].red = dv[rsum];
            output[yi].green = dv[gsum];
            output[yi].blue = dv[bsum];

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

            stackstart = stackpointer - radius + div;
            ir = stackstart % div; // same as sir

            routsum -= stack[ir][0];
            goutsum -= stack[ir][1];
            boutsum -= stack[ir][2];

            if (x == 0) vmin[y] = min(y + r1, hm) * w;
            ip = x + vmin[y];

            stack[ir][0] = r[ip];
            stack[ir][1] = g[ip];
            stack[ir][2] = b[ip];

            rinsum += stack[ir][0];
            ginsum += stack[ir][1];
            binsum += stack[ir][2];

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

            stackpointer = (stackpointer + 1) % div;
            ir = stackpointer; // same as sir

            routsum += stack[ir][0];
            goutsum += stack[ir][1];
            boutsum += stack[ir][2];

            rinsum -= stack[ir][0];
            ginsum -= stack[ir][1];
            binsum -= stack[ir][2];

            yi += w;
        }
    }

    // Unlocks everything
    AndroidBitmap_unlockPixels(env, bitmapIn);
    AndroidBitmap_unlockPixels(env, bitmapOut);

    LOGI ("Bitmap blurred.");
}

int min(int a, int b) {
    return a > b ? b : a;
}

int max(int a, int b) {
    return a > b ? a : b;
}

फिर इसे इस तरह उपयोग करें (com.insert.your.package.ClassName और functionToBlur नामक एक देशी फ़ंक्शन को राज्यों के ऊपर कोड के रूप में देखते हुए):

// Create a copy
Bitmap bitmapOut = bitmapIn.copy(Bitmap.Config.ARGB_8888, true);
// Blur the copy
functionToBlur(bitmapIn, bitmapOut, __radius);

यह RGB_8888 बिटमैप की अपेक्षा करता है!

RGB_565 बिटमैप का उपयोग करने के लिए, या तो पैरामीटर (yuck) पास करने से पहले एक परिवर्तित प्रतिलिपि बनाएँ, या rgb565इसके बजाय एक नए प्रकार का उपयोग करने के लिए फ़ंक्शन बदलें rgba:

typedef struct {
    uint16_t byte0;
} rgb565;

समस्या यह है कि यदि आप ऐसा करते हैं कि आप पढ़ नहीं सकते हैं .red, .greenऔर .blueपिक्सेल अब और नहीं, तो आपको बाइट को ठीक से पढ़ना होगा, डुह। जब मुझे पहले जरूरत थी, मैंने यह किया:

r = (pixels[x].byte0 & 0xF800) >> 8;
g = (pixels[x].byte0 & 0x07E0) >> 3;
b = (pixels[x].byte0 & 0x001F) << 3;

लेकिन ऐसा करने का शायद कुछ कम गूंगा तरीका है। मैं कम-स्तरीय सी कोडर का ज्यादा नहीं हूं, मुझे डर है।


धन्यवाद, इससे मुझे बहुत मदद मिली :)
दिमित्री ज़ेत्सेव

18
लेकिन इसके लिए बहुत अधिक मेमोरी की आवश्यकता होती है । की स्मृति की खपत परिवर्तन प्रकार कम करने के लिए r[wh], g[wh]और b[wh]करने के लिए uint8_t
दिमित्री ज़ेत्सेव

क्या आप मुझे दिखा सकते हैं कि आपकी Android.mk फ़ाइल कैसी दिखती है,pastebin.com
CQM

1
एंड्रॉइड एसडीके 17+ पर एक गाऊसी ब्लर के वर्किंग रेंडरस्क्रिप्ट उदाहरण के लिए यहां देखें: stackoverflow.com/questions/14988990/android-fast-bitmap-blur
मार्टिन मार्कोसिनी

2
एंड्रॉइड 2.2+ के लिए रेंडरस्क्रिप्ट समर्थन समर्थन के हिस्से के रूप में भी उपलब्ध है, इसलिए अब हर जगह इसका उपयोग न करने का कोई कारण नहीं है: android-developers.blogspot.com/2013/09/…
zeh

14

यह कोड मेरे लिए एकदम सही है

Bitmap tempbg = BitmapFactory.decodeResource(getResources(),R.drawable.b1); //Load a background.
Bitmap final_Bitmap = BlurImage(tempbg);


@SuppressLint("NewApi")
Bitmap BlurImage (Bitmap input)
{
    try
    {
    RenderScript  rsScript = RenderScript.create(getApplicationContext());
    Allocation alloc = Allocation.createFromBitmap(rsScript, input);

    ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(rsScript,   Element.U8_4(rsScript));
    blur.setRadius(21);
    blur.setInput(alloc);

    Bitmap result = Bitmap.createBitmap(input.getWidth(), input.getHeight(), Bitmap.Config.ARGB_8888);
    Allocation outAlloc = Allocation.createFromBitmap(rsScript, result);

    blur.forEach(outAlloc);
    outAlloc.copyTo(result);

    rsScript.destroy();
    return result;
    }
    catch (Exception e) {
        // TODO: handle exception
        return input;
    }

}

छवि को धुंधला करने का सबसे सरल तरीका (y)
VAdaihiep

12

अब आप जल्दी से ब्लर करने के लिए RenderScript लाइब्रेरी से 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;
    }
}

2
रेंडरस्क्रिप्ट संदर्भ को धब्बा विधि में नहीं बनाया जाना चाहिए, लेकिन वैधानिक रूप से प्रबंधित या विधि को दिया जाना चाहिए। (अगर आप प्रदर्शन को ध्यान में रखते हैं)
पैट्रिक फेवर

1
क्या आप इसका एक उदाहरण दे सकते हैं उपयोग है? जब मैं इसका उपयोग करने की कोशिश करता हूं तो मुझे निम्नलिखित त्रुटि मिलती है: java.lang.IllegalArgumentException: चौड़ाई और ऊंचाई> 0 होना चाहिए
डोनल रैफर्टी

10

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

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

यदि आपने रेंडरस्क्रिप्ट ऑब्जेक्ट को बनाया है तो यह और भी बेहतर / तेज़ होगा। हर बार जब आप एक छवि को धुंधला करना चाहते हैं, तो एक नए को इंस्टेंट करना अनावश्यक ओवरहेड (जावा ऑब्जेक्ट निर्माण / विनाश) जोड़ता है।
स्टीफन हाइन्स


4

यह उन सभी लोगों के लिए है, जिन्हें ScriptIntrinsicBlurकठोर गाऊसी धब्बा प्राप्त करने के लिए त्रिज्या बढ़ाने की आवश्यकता होती है ।

त्रिज्या को 25 से अधिक रखने के बजाय, आप छवि को स्केल कर सकते हैं और समान परिणाम प्राप्त कर सकते हैं। मैंने एक कक्षा लिखी जिसका नाम हैGaussianBlur । नीचे आप देख सकते हैं कि कैसे उपयोग करना है, और पूरे वर्ग का कार्यान्वयन।

उपयोग:

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

नहीं, अगर आप इमेज को स्केल करने के लिए बाद में स्केल करते हैं, तो आप
ब्लोर्ड

4

धन्यवाद @Yahel कोड के लिए। अल्फा चैनल धुंधला समर्थन के साथ एक ही विधि पोस्टिंग के रूप में यह मुझे कुछ समय लगा इसे सही ढंग से काम करने के लिए ताकि यह किसी का समय बचा सके:

/**
 * Stack Blur v1.0 from
 * http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
 * Java Author: Mario Klingemann <mario at quasimondo.com>
 * http://incubator.quasimondo.com
 * <p/>
 * created Feburary 29, 2004
 * Android port : Yahel Bouaziz <yahel at kayenko.com>
 * http://www.kayenko.com
 * ported april 5th, 2012
 * <p/>
 * 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.
 * <p/>
 * 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.
 * <p/>
 * If you are using this algorithm in your code please add
 * the following line:
 * Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
 */

public static 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 a[] = new int[wh];
    int rsum, gsum, bsum, asum, 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][4];
    int stackpointer;
    int stackstart;
    int[] sir;
    int rbs;
    int r1 = radius + 1;
    int routsum, goutsum, boutsum, aoutsum;
    int rinsum, ginsum, binsum, ainsum;

    for (y = 0; y < h; y++) {
        rinsum = ginsum = binsum = ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 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);
            sir[3] = 0xff & (p >> 24);

            rbs = r1 - Math.abs(i);
            rsum += sir[0] * rbs;
            gsum += sir[1] * rbs;
            bsum += sir[2] * rbs;
            asum += sir[3] * rbs;
            if (i > 0) {
                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];
                ainsum += sir[3];
            } else {
                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];
                aoutsum += sir[3];
            }
        }
        stackpointer = radius;

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

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

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

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

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

            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);
            sir[3] = 0xff & (p >> 24);

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

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

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

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

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

            yi++;
        }
        yw += w;
    }
    for (x = 0; x < w; x++) {
        rinsum = ginsum = binsum = ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 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];
            sir[3] = a[yi];

            rbs = r1 - Math.abs(i);

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

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

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

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

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

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

            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];
            sir[3] = a[p];

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

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

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

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

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

            yi += w;
        }
    }

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

    return (bitmap);
}

अभी भी उपकरणों में 'इंडेक्स ऑफ रेंज' के साथ> एचडीपीआई मूल स्रोत के रूप में
गेब्रियल फरेरा

4

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

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

2

भविष्य के गोगलर्स के लिए जो एनडीके दृष्टिकोण चुनते हैं - मुझे विश्वसनीय उल्लेख स्टैक्लबुर एल्गोरिथ्म लगता है। मैंने C ++ कार्यान्वयन पाया, जो यहाँ SSE पर निर्भर नहीं करता है - http://www.antigrain.com/__code/include/agg_blur.h.html#stack_blur_rgba32 जिसमें स्थिर तालिकाओं का उपयोग करके कुछ अनुकूलन शामिल हैं:

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

मैंने मल्टी-कोर सिस्टम के लिए स्टैब्लब्ल एल्गोरिथ्म का संशोधन किया है - यह यहाँ पाया जा सकता है http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/ के रूप में अधिक से अधिक उपकरणों 4 कोर - अनुकूलन दे 4x गति लाभ।


1

निकोलस POMEPUY सलाह। मुझे लगता है कि यह लिंक सहायक होगा: एंड्रॉइड डिज़ाइन के लिए धुंधला प्रभाव

जीथब में नमूना परियोजना

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private static Bitmap fastblur16(Bitmap source, int radius, Context ctx) {    
    Bitmap bitmap = source.copy(source.getConfig(), true);    
    RenderScript rs = RenderScript.create(ctx);
    Allocation input = Allocation.createFromBitmap(rs, source, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
    Allocation output = Allocation.createTyped(rs, input.getType());
    ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
    script.setRadius(radius);
    script.setInput(input);
    script.forEach(output);
    output.copyTo(bitmap);
    return bitmap;
}

हालांकि यह लिंक प्रश्न का उत्तर दे सकता है, लेकिन उत्तर के आवश्यक भागों को शामिल करना और संदर्भ के लिए लिंक प्रदान करना बेहतर है। लिंक-केवल उत्तर अमान्य हो सकते हैं यदि लिंक किए गए पृष्ठ बदल जाते हैं।
अमल मुरली

1
अमल मुरली, तुम सही हो। अब मेरी पोस्ट बदल दो। अच्छा है, कि आप न केवल नीच हैं, बल्कि टिप्पणी भी करते हैं।
यूरा शिंकरेव

1

हमने अलग-अलग जवाबों में ऊपर वर्णित रेंडरस्क्रिप्ट ब्लर को लागू करने की कोशिश की। हम वी 8 रेंडरस्क्रिप्ट संस्करण का उपयोग करने के लिए सीमित थे और इससे हमें बहुत परेशानी हुई।

  • जब भी हमने रेंडरस्क्रिप्ट का उपयोग करने की कोशिश की, सैमसंग S3 बेतरतीब ढंग से दुर्घटनाग्रस्त हो गया
  • अन्य उपकरणों (विभिन्न एपीआई के पार) ने यादृच्छिक रूप से अलग-अलग रंग के मुद्दों को दिखाया

मैं हमारे गंदे जावा-केवल संस्करण को साझा करना चाहता हूं जो धीमा है और इसे एक अलग थ्रेड पर किया जाना चाहिए और, यदि संभव हो, उपयोग से पहले और इसलिए जारी रखा जाए।

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

यह समाधान परिपूर्ण से बहुत दूर है, लेकिन इस तथ्य के आधार पर एक उचित धुंधला प्रभाव बनाता है, यह एक ही छवि के अत्यधिक पारदर्शी संस्करण को बमुश्किल पारदर्शी "तेज" संस्करण के ऊपर खींचता है। अल्फा मूल की दूरी पर निर्भर करता है।

आप अपनी आवश्यकताओं के लिए कुछ "मैजिक नंबर" को समायोजित कर सकते हैं। मैं सिर्फ उन सभी के लिए "समाधान" साझा करना चाहता था जिनके पास रेंडरस्क्रिप्ट के v8 समर्थन संस्करण के साथ समस्या है।


Im भी कुछ पुराने armeabi उपकरणों पर RenderScript के साथ एक समस्या हो रही है, लेकिन आपका समाधान बहुत अधिक स्मृति खपत है।
AsafK

0

उन लोगों के लिए जो अभी भी x86 चिपसेट पर रेंडरस्क्रिप्ट समर्थन पुस्तकालय के साथ समस्याएँ हैं, कृपया लाइब्रेरी के निर्माता द्वारा इस पोस्ट पर एक नज़र डालें। ऐसा लगता है कि उन्होंने जो फिक्स तैयार किया था, वह किसी भी तरह से बिल्ड टूल्स v20.0.0 के लिए नहीं बना था, इसलिए वह इसे मैन्युअल रूप से ठीक करने के लिए फाइलें प्रदान करता है और इसे कैसे करना है इसकी एक संक्षिप्त व्याख्या।

https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&groupby=&sort=&id=71347




0

मैंने पाया कि कंट्रास्ट, ब्राइटनेस और सैचुरेशन कम होने से धुंधली छवियां और अधिक सुंदर हो जाती हैं, इसलिए मैंने स्टैक ओवरफ्लो से विभिन्न तरीकों को जोड़ा और इसे बनाया ब्लर क्लास को जो ब्लर इमेज, बदलते ब्राइटनेस, सैचुरेशन, कॉन्ट्रास्ट और ब्लर इमेज के साइज को डील करता है। यह छवियों को बिटमैप से बिटमैप और इसके विपरीत में भी परिवर्तित कर सकता है।


0

I / o 2019 पर निम्नलिखित समाधान प्रस्तुत किया गया था:

/**
 * Blurs the given Bitmap image
 * @param bitmap Image to blur
 * @param applicationContext Application context
 * @return Blurred bitmap image
 */
@WorkerThread
fun blurBitmap(bitmap: Bitmap, applicationContext: Context): Bitmap {
    lateinit var rsContext: RenderScript
    try {

        // Create the output bitmap
        val output = Bitmap.createBitmap(
                bitmap.width, bitmap.height, bitmap.config)

        // Blur the image
        rsContext = RenderScript.create(applicationContext, RenderScript.ContextType.DEBUG)
        val inAlloc = Allocation.createFromBitmap(rsContext, bitmap)
        val outAlloc = Allocation.createTyped(rsContext, inAlloc.type)
        val theIntrinsic = ScriptIntrinsicBlur.create(rsContext, Element.U8_4(rsContext))
        theIntrinsic.apply {
            setRadius(10f)
            theIntrinsic.setInput(inAlloc)
            theIntrinsic.forEach(outAlloc)
        }
        outAlloc.copyTo(output)

        return output
    } finally {
        rsContext.finish()
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.