অ্যান্ড্রয়েড এসডিকে জন্য দ্রুত বিটম্যাপ ব্লার


185

বর্তমানে আমি এমন একটি অ্যান্ড্রয়েড অ্যাপ্লিকেশনটিতে বিকাশ করছি যা আমি অস্পষ্ট করতে একটি চিত্রের পিক্সেলগুলির মধ্য দিয়ে লুপ করছি। এটি 640x480 চিত্রে প্রায় 30 সেকেন্ড সময় নেয়।

অ্যান্ড্রয়েড মার্কেটে অ্যাপ্লিকেশনগুলি ব্রাউজ করার সময় আমি এমন একটি জুড়ে এসেছি যার মধ্যে একটি অস্পষ্ট বৈশিষ্ট্য রয়েছে এবং তাদের অস্পষ্টতা খুব দ্রুত (৫ সেকেন্ডের মতো) তাই তাদের অবশ্যই ঝাপসা করার একটি পৃথক পদ্ধতি ব্যবহার করা উচিত।

পিক্সেলগুলির মধ্য দিয়ে লুপিং ছাড়া অন্য কোনও দ্রুত উপায় কী জানেন?


2
দুর্ভাগ্যক্রমে চিত্রগুলি সর্বদা আলাদা থাকায় আমি সময়ের আগে অস্পষ্ট সংস্করণ তৈরি করতে পারব না। প্লাস আমি অস্পষ্টতার তীব্রতা সময়ের আগেই জানব না।
গ্রেগ

আপনি কি আপনার কোড পোস্ট করতে পারেন, এটি সম্ভবত অ্যালগরিদম / কোড যা অদক্ষ, 30 সেকেন্ড 640x480 চিত্রের মধ্য দিয়ে যেতে ধীর, আমি ভাবতাম 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) আপনার সম্পূর্ণ চিত্রটি লোড করা দরকার যা ধীর - ইন-নমুনা আকারের সাথে লোডিং ব্যবহার করুন এবং বিটম্যাপফ্যাক্টরি.ডেকোড রিসোর্স (), এটি এর থেকে আরও উন্নত সমাধান।
প্যাট্রিক ফ্যাভরে

300

ভবিষ্যতের গুগলারের জন্য, আমি এখানে একটি আলগোরিদিম রেখেছি যা আমি কোসিমন্ডো থেকে পোর্ট করেছি। এটি একটি বাক্সের ঝাপসা এবং গাউসিয়ান ব্লারের মধ্যে এক ধরনের মিশ্রণ, এটি খুব সুন্দর এবং খুব দ্রুত।

অ্যারেআইন্ডেক্সআউটআউটফাউন্ডস এক্সেকশন সমস্যাটির সম্মুখীন লোকদের জন্য আপডেট: মন্তব্যগুলিতে @ অ্যান্থনিক্রার এই তথ্য সরবরাহ করে:

আমি খুঁজে পেয়েছি যে স্ট্যাথমেথ.এবস বা অন্য কিছু অ্যাবস প্রয়োগের সাথে ম্যাথ.এবস প্রতিস্থাপন করে ক্র্যাশ ঘটে না।

/**
 * 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 এর চেয়ে বড় ব্যাসার্ধের জন্য কখনও কখনও আপনি অ্যারেআইন্ডেক্সআউটআউটবাউন্ডসেক্সপশন পান। আমি সমস্যাটি চিহ্নিত করার চেষ্টা করব।
মাইকেল

7
@ মিশেললিবারম্যান আমিও একই সমস্যার মুখোমুখি হয়েছি ound এখনও খুঁজে কেন? "g [yi] = ডিভি [জিএসএম];" -> ত্রুটি: java.lang.ArrayIndexOutOfBoundsException: দৈর্ঘ্য = 112896; সূচক = 114021
2851

2
পরিচিত অ্যারেআইন্ডেক্স আউট অফফাউন্ডস এক্সসেপশনে ছুটে এসেছিল এবং কিছু বিশ্লেষণের পরে, আমি বিশ্বাস করি যে এটি ডালভিক ভিএম দ্বারা একটি ভুল অপ্টিমাইজেশনের কারণে হয়েছিল। ইন forলুপ অবিলম্বে খারাপ ডি-রেফারেন্স সামনে, হয় হিসাব rbsপরিবর্তনশীল বা হিসাব gsum, rsumঅথবা bsumভেরিয়েবল সম্পন্ন ঠিক না হচ্ছে। আমি দেখেছি যে প্রতিস্থাপন Math.absসঙ্গে StrictMath.absঅথবা অন্য কোনো absপ্রয়োগ, ক্র্যাশ ঘটবে না। যেহেতু StrictMath.absনিজেই এটি প্রতিনিধি Math.abs
anthonycr

255

Android ব্লার গাইড 2016 Bl

প্রদর্শনী / বেঞ্চমার্ক অ্যাপ সঙ্গে এবং উত্স GitHub থেকেআমি বর্তমানে যে অস্পষ্ট কাঠামোটিতে কাজ করছি তা পরীক্ষা করে দেখুন: ডালি

অনেকগুলি পরীক্ষার পরে আমি এখন নিরাপদে আপনাকে এমন কিছু দৃ recommendations় প্রস্তাব দিতে পারি যা অ্যান্ড্রয়েড ফ্রেমওয়ার্ক ব্যবহার করার সময় অ্যান্ড্রয়েডে আপনার জীবনকে আরও সহজ করে তুলবে।

একটি ডাউনস্কেল বিটম্যাপ লোড করুন এবং ব্যবহার করুন (খুব ঝাপসা ছবিগুলির জন্য)

বিটম্যাপের পুরো আকারটি কখনই ব্যবহার করবেন না। চিত্রটি যত বেশি ততই ঝাপসা হওয়ার দরকার এবং ততোধিক ঝাপসা ব্যাসার্ধের উচ্চতর হওয়া প্রয়োজন এবং সাধারণত, অ্যালগরিদম যত বেশি বেশি কালচার ব্যাসার্ধ লাগে তত বেশি।

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, ...) রাখুন। আরও জন্য গুগল ডক দেখুন

আরেকটি সত্যিই বড় সুবিধা হ'ল বিটম্যাপ লোড করা সত্যিই দ্রুত হবে। আমার প্রারম্ভিক অস্পষ্টতার পরীক্ষায় আমি অনুভব করেছি যে পুরো অস্পষ্ট প্রক্রিয়াটির মধ্যে সবচেয়ে দীর্ঘ সময়টি ছিল চিত্র লোড। সুতরাং ডিস্ক থেকে 1920x1080 চিত্রটি লোড করতে আমার নেক্সাস 5 এর 500 মিমি দরকার ছিল যখন অস্পষ্টতা কেবল আরও 250 এমএস বা আরও গ্রহণ করেছিল।

রেন্ডারস্ক্রিপ্ট ব্যবহার করুন

রেন্ডারস্ক্রিপ্ট সরবরাহ করে ScriptIntrinsicBlurযা কোনও গাউসিয়ান ব্লার ফিল্টার। এটিতে ভাল ভিজ্যুয়াল মানের রয়েছে এবং আপনি অ্যান্ড্রয়েডে বাস্তবতার চেয়ে দ্রুততমতমতম গতি পান। গুগল দাবি করেছে যে "একটি মাল্টিথ্রেডেড সি বাস্তবায়নের চেয়ে সাধারণত 2-3x দ্রুত এবং প্রায়শই জাভা প্রয়োগের চেয়ে 10x + দ্রুত" । রেন্ডারস্ক্রিপ্টটি সত্যই পরিশীলিত (দ্রুততম প্রসেসিং ডিভাইস (জিপিইউ, আইএসপি, ইত্যাদি ব্যবহার করে) ইত্যাদি) এবং এটিতে 2.8 এর সাথে সামঞ্জস্যপূর্ণ করার জন্য ভি 8 সাপোর্ট লাইব্রেরিও রয়েছে । কমপক্ষে তত্ত্বের ক্ষেত্রে, আমার নিজের পরীক্ষাগুলি এবং অন্যান্য ডেভস থেকে প্রাপ্ত প্রতিবেদনের মাধ্যমে মনে হয় যে রেন্ডারস্ক্রিপ্ট অন্ধভাবে ব্যবহার করা সম্ভব নয়, যেহেতু হার্ডওয়ার / ড্রাইভারের বিভাজন কিছু ডিভাইসগুলিতে এমনকি উচ্চতর এসডিকে এলভিএল (যেমন আমার ছিল 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);

গ্রেডলের সাথে ভি 8 সমর্থন ব্যবহার করার সময়, যা গুগলের দ্বারা বিশেষত সুপারিশ করা হয়েছে "কারণ সেগুলিতে সর্বশেষ উন্নতি রয়েছে" , আপনাকে কেবলমাত্র আপনার বিল্ড স্ক্রিপ্টে 2 টি লাইন যুক্ত করতে হবে android.support.v8.renderscriptএবং বর্তমান বিল্ড সরঞ্জামগুলি ব্যবহার করতে হবে ( অ্যান্ড্রয়েড গ্রেডল প্লাগইন ভি 14 + এর জন্য আপডেট সিনট্যাক্স )

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

নেক্সাস 5-তে সরল মাপদণ্ড - বিভিন্ন অন্যান্য জাভা এবং রেন্ডারস্ক্রিপ্ট বাস্তবায়নের সাথে রেন্ডারস্ক্রিপ্টের তুলনা করা:

বিভিন্ন পিক আকারে অস্পষ্টতার জন্য গড় রানটাইম বিভিন্ন পিক আকারে অস্পষ্টতার জন্য গড় রানটাইম

অস্পষ্ট হতে পারে যা প্রতি সেকেন্ডে মেগাপিক্সেল অস্পষ্ট হতে পারে যা প্রতি সেকেন্ডে মেগাপিক্সেল

প্রতিটি মান 250 রাউন্ডের গড়। RS_GAUSS_FASTহয় ScriptIntrinsicBlur(এবং প্রায় সবসময় দ্রুততম), অন্যদের যে দিয়ে শুরু RS_বেশিরভাগই সহজ কার্নেলের সাথে বিভিন্ন বস্তু একত্র পাকান বাস্তবায়নের হয়। অ্যালগরিদমের বিবরণ এখানে পাওয়া যাবে । এটি নিখুঁতভাবে অস্পষ্ট নয়, কারণ একটি ভাল অংশটি ময়লা ফেলা আবর্জনা সংগ্রহ। এটি এখানে এটি দেখতে পাওয়া যায় ( ScriptIntrinsicBlurপ্রায় 500 রাউন্ড সহ 100x100 চিত্রে)

এখানে চিত্র বর্ণনা লিখুন

স্পাইকগুলি গিসি হয়।

আপনি নিজের জন্য পরীক্ষা করতে পারেন, বেঞ্চমার্ক অ্যাপটি প্লেস্টোরে রয়েছে: ব্লারবেঞ্চমার্ক

যেখানেই সম্ভব বিটম্যাপ পুনরায় ব্যবহার করুন (যদি প্রিও: পারফরম্যান্স> মেমরি পদচিহ্ন)

আপনার যদি লাইভ অস্পষ্ট বা অনুরূপ জন্য একাধিক অস্পষ্ট প্রয়োজন হয় এবং আপনার স্মৃতি মঞ্জুর করে এটি একাধিকবার ড্রয়াবল থেকে বিটম্যাপটি লোড না করে তবে এটি সদস্যের পরিবর্তনশীলটিতে "ক্যাশেড" রাখুন keep এক্ষেত্রে সর্বদা একই ভেরিয়েবলগুলি ব্যবহার করার চেষ্টা করুন, ন্যূনতম জঞ্জাল সংগ্রহের জন্য।

ফাইল বা অঙ্কনযোগ্য থেকে inBitmapলোড করার সময় নতুন বিকল্পটিও পরীক্ষা করে দেখুন যা বিটম্যাপ মেমরিটিকে পুনরায় ব্যবহার করবে এবং আবর্জনা সংগ্রহের সময় সাশ্রয় করবে।

ঝাপসা থেকে ধারালো থেকে মিশ্রণের জন্য

সহজ এবং নিষ্পাপ পদ্ধতিটি হ'ল 2 ImageViews, একটি ঝাপসা এবং আলফা তাদের বিবর্ণ করা। তবে আপনি যদি এমন আরও পরিশীলিত চেহারা চান যা তীক্ষ্ণ থেকে ঝাপসা হয়ে মসৃণভাবে ফিকে হয়ে যায়, তবে তার মুজেই অ্যাপে কীভাবে এটি করা যায় সে সম্পর্কে রোমান নুরিকের পোস্টটি দেখুন

মূলত তিনি ব্যাখ্যা করেছেন যে তিনি কিছু ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ঝাপিয়ে পড়েছেন এবং এনিমেশনটিতে কীফ্রেম হিসাবে ব্যবহার করেন যা সত্যই মসৃণ লাগে।

ডায়াগ্রাম যেখানে নূরিক তার পদ্ধতির ব্যাখ্যা করে


1
প্রথমত, আপনার কঠোর পরিশ্রমের জন্য ধন্যবাদ! তবে আমি একটি প্রশ্ন পেয়েছি: "কারণ এটি USAGE_SHARED মোড ব্যবহার করে যা স্মৃতি পুনরায় ব্যবহার করে"। আপনি অবিচ্ছিন্ন USAGE_SHARED কোথায় পেয়েছেন? আমি এটি কোথাও খুঁজে পেলাম না।
কিছু নুব শিক্ষার্থী

2
আমি এটি পেয়েছি, USAGE_SHARED কেবল সমর্থন.এইউ 8. রেন্ডারস্ক্রিপ্টে উপলব্ধ
কিছু নুব শিক্ষার্থী

2
রেন্ডারস্ক্রিপ্ট দ্রুত গাউসিয়ান ব্লার লো এন্ড ডিভাইসগুলিতে সি মেমরি বরাদ্দ ত্রুটির সাথে ব্যর্থ। সরবরাহিত প্লে স্টোর অ্যাপ্লিকেশনটি ব্যবহার করে জেডটিই জেড 992 (অ্যান্ড্রয়েড 4.1.1) এবং কায়সেরা রাইজ (অ্যান্ড্রয়েড 4.0.4) এ পরীক্ষিত। এছাড়াও স্যামসং গ্যালাক্সি এস 3 মিনিতে ব্যর্থতার প্রতিবেদন ছিল। যেহেতু সি স্তরটিতে ত্রুটিগুলি দেখা দেয়, তাই এগুলি জাভা ব্যতিক্রম হিসাবে আটকাতে পারে না, অর্থাত কোনও অ্যাপ ক্রাশ অনিবার্য। দেখে মনে হচ্ছে রেন্ডারস্ক্রিপ্ট উত্পাদন ব্যবহারের জন্য প্রস্তুত নাও হতে পারে।
থিও

4
নতুন গ্রেড সংস্করণগুলির জন্য, ব্যবহার করুন renderscriptSupportModeEnabled trueবা এটি তৈরি করবে না! আমি সর্বদা অনুসন্ধান!
সেব


53

সম্পাদনা (এপ্রিল ২০১৪): এটি এমন একটি প্রশ্ন / উত্তর পৃষ্ঠা যা এখনও মনে হচ্ছে প্রচুর হিট। আমি জানি আমি সবসময় এই পোস্টের জন্য উপার্জন করছি। তবে আপনি যদি এটি পড়ছেন তবে আপনার এখানে পোস্ট করা উত্তরগুলি উপলব্ধি করতে হবে (আমার এবং স্বীকৃত উত্তর উভয়ই) পুরানো। আপনি দক্ষ দাগ বাস্তবায়ন করতে চান, আজ , আপনি RenderScript ব্যবহার করা উচিত পরিবর্তে NDK বা জাভা। রেন্ডারস্ক্রিপ্ট অ্যান্ড্রয়েড ২.২++ ( অ্যান্ড্রয়েড সমর্থন লাইব্রেরি ব্যবহার করে ) এ চলে, সুতরাং এটি ব্যবহার না করার কোনও কারণ নেই।

পুরানো উত্তর অনুসরণ, কিন্তু এটি পুরানো হিসাবে সাবধান।


ভবিষ্যতের জন্য- গুগলারের জন্য, এখানে আমি ক্যাসিমন্ডোর অ্যালগরিদমের ইয়াহেলের বন্দর থেকে পোর্ট করেছি, তবে এনডিকে ব্যবহার করেছি al এটি অবশ্যই ইয়াহেলের উত্তরের উপর ভিত্তি করে। তবে এটি নেটিভ সি কোড চালাচ্ছে, তাই এটি আরও দ্রুত। অনেক দ্রুত. মত, 40 গুণ দ্রুত।

আমি দেখতে পেয়েছি যে এনডিকে ব্যবহার করে সমস্ত চিত্র ম্যানিপুলেশন অ্যান্ড্রয়েডে কীভাবে করা উচিত ... প্রথমে এটি প্রয়োগ করা কিছুটা বিরক্তিকর ( এখানে জেএনআই এবং এনডিকে ব্যবহারের একটি দুর্দান্ত টিউটোরিয়াল পড়ুন ) তবে আরও ভাল, এবং জন্য বাস্তব সময় কাছাকাছি অনেক জিনিস.

রেফারেন্সের জন্য, ইয়াহেলের জাভা ফাংশনটি ব্যবহার করে, আমার 480x532 পিক্সেল চিত্রটি 10 ​​এর অস্পষ্ট ব্যাসার্ধের সাথে ঝাপসা হতে 10 সেকেন্ড সময় নিয়েছে তবে নেটিভ সি সংস্করণটি ব্যবহার করে এটি 250 মিমি নিয়েছে। এবং আমি নিশ্চিত যে এটি আরও অপ্টিমাইজ করা যায় ... আমি জাভা কোডটির একটি বোবা রূপান্তরটি করেছি, সম্ভবত কিছু ম্যানিপুলেশনগুলি সংক্ষিপ্ত করা যেতে পারে, পুরো জিনিসটি রিফ্যাক্টারে খুব বেশি সময় ব্যয় করতে চান না।

#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 এবং একটি ফাংশনটোবরুর নামে একটি নেটিভ ফাংশন হিসাবে বিবেচিত):

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

এটি একটি আরজিবি_8888 বিটম্যাপ প্রত্যাশা করে!

একটি আরজিবি_৫65 bit বিটম্যাপ ব্যবহার করতে হয়, প্যারামিটার (ইয়াক) পাস করার আগে রূপান্তরিত অনুলিপি তৈরি করুন বা এর rgb565পরিবর্তে একটি নতুন ধরণের ব্যবহার করতে ফাংশনটি পরিবর্তন করুন rgba:

typedef struct {
    uint16_t byte0;
} rgb565;

সমস্যা হল যদি আপনি না যে, আপনি নিজে পড়তে পারবেন .red, .greenএবং .blueআর পিক্সেল, আপনি বাইট সঠিকভাবে, duh পড়া প্রয়োজন। যখন আমার আগে এটির প্রয়োজন ছিল, আমি এটি করেছি:

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
দিমিত্রি জায়েতসেভ

আপনার অ্যান্ড্রয়েড.এমকে ফাইলটি দেখতে কেমন তা আমাকে দেখাতে পারেনpastebin.com
CQM

1
অ্যান্ড্রয়েড এসডিকে 17+ তে গাউসিয়ান ব্লারের একটি কার্যকারী রেন্ডারস্ক্রিপ্ট উদাহরণের জন্য এখানে দেখুন: stackoverflow.com/questions/14988990/android-fast-bitmap-blur
মার্টিন মার্কনকিনি

2
রেন্ডারস্ক্রিপ্ট অ্যানড্রইড ২.২++ এর জন্য সমর্থন লিবের অংশ হিসাবেও উপলব্ধ, তাই এটি আর
কোথাও

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

আপনি এখন ব্যবহার করতে পারেন ScriptIntrinsicBlur দ্রুত দাগ RenderScript লাইব্রেরি থেকে। রেন্ডারস্ক্রিপ্ট এপিআই কীভাবে অ্যাক্সেস করবেন তা এখানে । নিম্নলিখিতটি আমি দেখি এবং বিটম্যাপগুলি অস্পষ্ট করতে তৈরি একটি ক্লাস:

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.IllegalArgumentEception: প্রস্থ এবং উচ্চতা অবশ্যই> 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;
}
    }

কোন যদি আপনি আপ স্কেল করা হয় পরে আপনি একটি blured ইমেজ পরিবর্তে :( একটি ব্লকি ইমেজ পুনরুদ্ধার করবে ইমেজ আনুপাতিক হারে কমান
লোকি

4

কোডের জন্য @ ইয়াহেলকে ধন্যবাদ। আলফা চ্যানেল অস্পষ্ট সমর্থন সহ একই পদ্ধতি পোস্ট করা কারণ এটি সঠিকভাবে কাজ করতে আমার কিছুটা সময় লেগেছে যাতে এটি কারও সময় বাঁচাতে পারে:

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

ভবিষ্যতের গুগলারের জন্য যারা এনডিকে পদ্ধতির পছন্দ করেন - আমি নির্ভরযোগ্য স্ট্যাকব্লুর অ্যালগরিদম খুঁজে পাই। আমি সি ++ বাস্তবায়ন পেয়েছি যা এখানে এসএসই-তে নির্ভর করে না - http://www.antigrain.com/__code/incolve/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-mult-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 রেন্ডারস্ক্রিপ্ট সংস্করণটি ব্যবহারের মধ্যে সীমাবদ্ধ ছিলাম এবং এটি আমাদের প্রচুর সমস্যায় ফেলেছিল।

  • যখনই আমরা রেন্ডারস্ক্রিপ্টটি ব্যবহার করার চেষ্টা করেছি স্যামসুং এস 3 এলোমেলোভাবে ক্র্যাশ হয়েছিল
  • অন্যান্য ডিভাইস (বিভিন্ন API গুলি জুড়ে) এলোমেলোভাবে বিভিন্ন রঙের সমস্যা দেখিয়েছে

আমি আমাদের নোংরা জাভা-শুধুমাত্র সংস্করণটি ভাগ করতে চাই যা ধীর এবং এটি পৃথক থ্রেডে করা উচিত এবং যদি সম্ভব হয় তবে ব্যবহারের আগে এবং তাই অবিচল থাকে।

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

এই সমাধানটি নিখুঁত থেকে দূরে তবে সত্যের উপর ভিত্তি করে যুক্তিসঙ্গত অস্পষ্ট প্রভাব তৈরি করে যে এটি সবেমাত্র স্বচ্ছ "তীক্ষ্ণ" সংস্করণের শীর্ষে একই চিত্রের অত্যন্ত স্বচ্ছ সংস্করণ আঁকবে। আলফা মূলের দূরত্বের উপর নির্ভর করে।

আপনি আপনার প্রয়োজনের সাথে কিছু "ম্যাজিক নম্বর" সামঞ্জস্য করতে পারেন। রেন্ডারস্ক্রিপ্টের ভি 8 সমর্থন সংস্করণ নিয়ে সমস্যা আছে এমন প্রত্যেকের জন্য আমি সেই "সমাধান" ভাগ করে নিতে চেয়েছিলাম।


কিছু পুরানো আরমেবি ডিভাইসে রেন্ডারস্ক্রিপ্ট নিয়ে আমারও সমস্যা রয়েছে, তবে আপনার সমাধানটি খুব স্মৃতিশক্তি গ্রহণ করছে।
আসফকে

0

X86 চিপসেটগুলিতে রেন্ডারস্ক্রিপ্ট সমর্থন লাইব্রেরিতে এখনও সমস্যা রয়েছে তাদের জন্য, দয়া করে গ্রন্থাগারের স্রষ্টার এই পোস্টটি দেখুন। দেখে মনে হচ্ছে যে সে প্রস্তুত করা ফিক্সটি কোনওভাবে বিল্ড টুলস ভি ২০.০.০ তে তৈরি করেনি, সুতরাং তিনি ফাইলগুলি ম্যানুয়ালি ঠিক করার জন্য এবং কীভাবে এটি করবেন তার একটি সংক্ষিপ্ত বিবরণ সরবরাহ করে।

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

এখানে রেন্ডারস্ক্রিপ্ট ব্যবহার করে রিয়েলটাইম ব্লারিং ওভারলে রয়েছে যা যথেষ্ট দ্রুত বলে মনে হচ্ছে।

https://github.com/mmin18/RealtimeBlurView


0

আমি দেখতে পেলাম যে কমতে থাকা বৈসাদৃশ্য, nessজ্জ্বল্য এবং স্যাচুরেশন কিছুটা অস্পষ্ট চিত্রগুলিকে আরও সুন্দর করে তোলে তাই আমি স্ট্যাক ওভারফ্লো থেকে বিভিন্ন পদ্ধতি একত্রিত করেছি এবং এই অস্পষ্ট ক্লাসটি তৈরি করেছি যা অস্পষ্ট চিত্রগুলির পরিবর্তন, উজ্জ্বলতা, স্যাচুরেশন, বিপরীতে এবং অস্পষ্ট চিত্রগুলির আকারের সাথে সম্পর্কিত। এটি চিত্রগুলি অঙ্কনযোগ্য থেকে বিটম্যাপ এবং বিপরীতে রূপান্তর করতে পারে।


0

আই / ও 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()
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.