Android SDK için Hızlı Bitmap Bulanıklığı


185

Şu anda geliştirdiğim bir Android uygulamasında, görüntüyü bulanıklaştırmak için pikseller arasında dolaşıyorum. 640x480 boyutundaki bir görüntüde bu yaklaşık 30 saniye sürer.

Android Market'teki uygulamalara göz atarken bir bulanıklık özelliği içeren bir bulanıklıkla karşılaştım ve bulanıklıkları çok hızlı (5 saniye gibi), bu yüzden farklı bir bulanıklaştırma yöntemi kullanıyor olmalılar.

Pikseller arasında geçiş yapmaktan daha hızlı bir yol bilen var mı?


2
Ne yazık ki görüntüler her zaman farklı olacak, bu yüzden önceden bulanık bir versiyon oluşturamayacağım. Artı, bulanıklık yoğunluğunu önceden de bilmiyorum
Greg

Kodunuzu gönderebilir misiniz, belki de algoritma / kod verimsizdir, 640x480 görüntüden geçmek için 30 saniye yavaştır, 5 saniyenin yavaş olduğunu düşünürdüm ama sonra tekrar işlemciye bağlıdır.
vickirk

Yanıtlar:


78

Bu karanlıkta bir çekim, ancak görüntüyü küçültüp tekrar büyütmeyi deneyebilirsiniz. Bu ile yapılabilir Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter). Filtre parametresini true olarak ayarladığınızdan emin olun. Daha hızlı olabilmesi için yerel kodda çalışır.


5
Bazı testlerden ve bunu yaptığım bulanıklaştırmadan sonra benim için yeterince iyi çalışıyor ve hızlı. Teşekkürler!
Greg

4
İyi çalışıyorsa. Neden verimsiz olduğunun alt kısmına asla ulaşamadığımız için bir utanç.
vickirk

CreateScaledBitmap'i denemek ve görüntüyü aynı boyutta bırakmak isteyebilirsiniz. Benim için bulanıklaştırıyor :-(
Casebash

1
İşte "filtre" argümanının anlamı üzerine bir tartışma: stackoverflow.com/questions/2895065
user1364368

4
Bu, 2 nedenden ötürü tam olarak elde edilebilecek bir yol değildir: 1) muhtemelen sadece küçültülmüş bir tane kullanmanıza rağmen tam görüntünün belleğine ihtiyacı vardır 2) daha yavaş olan tam görüntüyü yüklemeniz gerekir - inSampleSize ile yükleme kullanın ve Bunun için çok üstün bir çözüm olan BitmapFactory.decodeResource ().
Patrick Favre

303

Gelecekteki Google çalışanları için, Quasimondo'dan aldığım bir algoritma. Bir kutu bulanıklığı ve bir gauss bulanıklığı arasında bir karışım, çok güzel ve oldukça hızlı.

ArrayIndexOutOfBoundsException sorunuyla karşılaşan insanlar için güncelleme: yorumlarda @ @anthonycr bu bilgileri sağlar:

Math.abs'ı StrictMath.abs veya başka bir abs uygulamasıyla değiştirerek çökmenin gerçekleşmediğini buldum.

/**
 * 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
Teşekkürler Yahel. Sorunumu çözdün. Tekrar teşekkürler.
Yog Guru

1
yarıçap olarak ne geçmeliyim?
krisDrOid

16
1'den büyük yarıçap için bazen ArrayIndexOutOfBoundsException alabilirsiniz. Sorunu tanımlamaya çalışacağım.
MikeL

7
@MichaelLiberman Ben de aynı sorunla karşılaştı. "g [yi] = dv [gsum];" -> hata: java.lang.ArrayIndexOutOfBoundsException: length = 112896; endeks = 114021
see2851

2
Bilinen ArrayIndexOutOfBoundsException içine koştu ve bazı analizlerden sonra, bunun Dalvik VM tarafından yanlış bir optimizasyondan kaynaklandığına inanıyorum. Gelen fordöngü hemen kötü dereference önce hesaplanması ya rbsdeğişkenin veya hesaplanması gsum, rsumya bsumdeğişkenler bitti haklı olmak değildir. Ben yerine veya başka bir uygulama Math.absile değiştirerek , çökme olmadığını buldum . Yana delegeler kendisini kötü bir optimizasyon olmalı gibi görünüyor. StrictMath.absabsStrictMath.absMath.abs
anthonycr

255

Android Blur Kılavuzu 2016

Github üzerinde Vitrin / Benchmark App ve Kaynak ile . Ayrıca şu anda üzerinde çalıştığım Blur çerçevesine de göz atın: Dali .

Çok denedikten sonra artık Android Framework'ü kullanırken Android'de hayatınızı kolaylaştıracak bazı sağlam önerilerde bulunabiliyorum.

Küçültülmüş Bitmap Yükleme ve Kullanma (çok bulanık görüntüler için)

Asla bitmap boyutunun tamamını kullanmayın. Görüntü ne kadar büyük olursa bulanıklaşmaya o kadar çok ihtiyaç duyulur ve bulanıklaştırma yarıçapı ne kadar yüksek olursa genellikle algoritma o kadar uzun sürer.

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

Bu, bitmap'i inSampleSize8 ile yükleyecektir , böylece orijinal görüntünün sadece 1 / 64'ü. inSampleSizeİhtiyaçlarınıza uygun olanları test edin, ancak ölçeklendirme nedeniyle kalitenin düşmesini önlemek için 2 ^ n (2,4,8, ...) tutun. Daha fazla bilgi için Google dokümanına bakın

Bir başka gerçekten büyük avantaj, bitmap yüklemenin gerçekten hızlı olması. Erken bulanıklaştırma testimde, tüm bulanıklaştırma işlemi boyunca en uzun sürenin görüntü yükleme olduğunu anladım. Bu nedenle, bir 1920x1080 görüntüyü diskten yüklemek için, Nexus 5 cihazımın 500ms'ye ihtiyacı vardı, bulanıklaştırma sadece 250 ms sürdü.

Yorumlama Kullan

Renderscript ScriptIntrinsicBlurbir Gauss bulanıklaştırma filtresi sağlar. İyi bir görsel kaliteye sahiptir ve Android'de gerçekçi bir şekilde elde ettiğiniz en hızlıdır. Google, "çok iş parçacıklı bir C uygulamasından genellikle 2-3 kat daha hızlı ve genellikle bir Java uygulamasından 10 kat daha hızlı" olduğunu iddia ediyor . Renderscript gerçekten sofistike (en hızlı işlem cihazı (GPU, ISS, vb.), Vb. Kullanılarak) ve ayrıca 2.2'ye kadar uyumlu olmasını sağlayan v8 destek kütüphanesi de var. . En azından teoride, kendi testlerim ve diğer geliştiricilerden gelen raporlarım sayesinde Renderscript'i körü körüne kullanmanın mümkün olmadığı anlaşılıyor, çünkü donanım / sürücü parçalanması bazı cihazlarda, daha yüksek sdk lvl ile bile sorunlara neden gibi görünüyor (örneğin, 4.1 Nexus S ile ilgili sorunlar) dikkatli olun ve birçok cihazda test edin. İşte başlamanıza yardımcı olacak basit bir örnek:

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

"En son geliştirmeleri içerdikleri için" Google tarafından özellikle önerilen Gradle ile v8 desteğini kullanırken, derleme komut dosyanıza yalnızca 2 satır eklemeniz ve android.support.v8.renderscriptmevcut oluşturma araçlarıyla ( android Gradle eklentisi v14 + için güncellenmiş sözdizimi ) kullanmanız gerekir.

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

Nexus 5'te basit bir karşılaştırma - RenderScript'i farklı java ve Renderscript uygulamalarıyla karşılaştırma:

Farklı resim boyutlarında bulanıklık başına ortalama çalışma süresi Farklı resim boyutlarında bulanıklık başına ortalama çalışma süresi

Saniyede bulanıklaştırılabilen megapiksel Saniyede bulanıklaştırılabilen megapiksel

Her değer 250 raund ortalama. RS_GAUSS_FASTile başlayan ScriptIntrinsicBlur(ve neredeyse her zaman en hızlısıdır), diğerleriyle başlayanlar RS_çoğunlukla basit çekirdeklerle konvolüsyonlardır. Algoritmaların detaylarını burada bulabilirsiniz . İyi bir kısmı ölçülen çöp toplama olduğu için bu tamamen bulanık değildir. Bu, burada görülebilir ( ScriptIntrinsicBluryaklaşık 500 mermi ile 100x100 görüntü üzerinde)

resim açıklamasını buraya girin

Sivri uçlar gc'dir.

Kendiniz için kontrol edebilirsiniz, karşılaştırma uygulaması playstore'da: BlurBenchmark

Bitmap'i mümkün olan her yerde yeniden kullanır (prio: performans> bellek kapladığı yer)

Canlı bir bulanıklık veya benzeri için birden fazla bulanıklığa ihtiyacınız varsa ve belleğiniz bitmap'i çekmecelerden birden fazla yüklemesine izin veriyorsa, ancak bir üye değişkeninde "önbelleğe alınmış" kalmasını sağlar. Bu durumda, çöp toplama işlemini minimumda tutmak için her zaman aynı değişkenleri kullanmaya çalışın.

Ayrıca yüklerken yeni seçeneğe de göz inBitmapatın bitmap belleğini yeniden kullanacak ve çöp toplama zamanından tasarruf edecek bir dosyadan veya çekmeceden atın.

Keskinden bulanıklığa karıştırmak için

Basit ve naif yöntem sadece 2 ImageViews, bir bulanık ve alfa solmasıdır. Ancak keskinden bulanıklığa yumuşak bir şekilde kaybolan daha sofistike bir görünüm istiyorsanız, Roman Nurik'in Muzei uygulamasında olduğu gibi nasıl yapılacağı ile ilgili gönderisine göz atın. .

Temel olarak, farklı bulanıklaştırma uzantılarına sahip bazı kareleri önceden bulanıklaştırdığını ve gerçekten pürüzsüz görünen bir animasyonda ana kareler olarak kullandığını açıklıyor.

Nurik'in yaklaşımını açıkladığı diyagram


1
Her şeyden önce, sıkı çalışmanız için teşekkürler! Ama bir sorum var: "çünkü belleği yeniden kullanan USAGE_SHARED modunu kullanıyor". USAGE_SHARED sabitini nerede buldunuz? Hiçbir yerde bulamadım.
Bazı Noob Öğrenci

2
Buldum, USAGE_SHARED sadece support.v8.renderscript içinde mevcut
Bazı Noob Öğrenci

2
Oluşturma hızlı Gauss bulanıklığı düşük uç aygıtlarda C bellek ayırma hatalarıyla başarısız olur. Sağlanan Play Store uygulamasını kullanarak ZTE Z992 (Android 4.1.1) ve Kyocera Rise (Android 4.0.4) üzerinde test edildi. Ayrıca Samsung Galaxy S3 mini hakkında bir arıza raporu vardı. C katmanında hatalar oluştuğundan, Java'da istisna olarak yakalanamazlar, bu da bir uygulama kilitlenmesinin kaçınılmaz olduğu anlamına gelir. Görünüşe göre RenderScript üretim kullanımına hazır olmayabilir.
Theo

4
daha yeni sürümler için kullanın renderscriptSupportModeEnabled trueveya oluşturmaz! Sonsuza dek aradım!
seb

3
Bu çözümü denediğimde bulanık bir bitmap almak yerine gökkuşağı renkli bir bitmap aldım . Bu sorunu yaşayan başka biri var mı? Varsa nasıl düzelttiniz?
HaloMediaz

53

EDIT (Nisan 2014): Bu, hâlâ çok sayıda isabet alan bir soru / cevap sayfası. Bu yazı için hep vekalet alıyorum. Ancak bunu okuyorsanız, burada yayınlanan cevapların (hem benim hem de kabul edilen cevap) güncel olmadığını anlamanız gerekir . Eğer verimli bulanıklık uygulamak istiyorsanız bugün , sen RenderScript kullanmalısınız yerine NDK veya Java. RenderScript Android 2.2 ve sonraki sürümlerinde çalışır ( Android Destek Kitaplığı'nı kullanarak) ) çalışır, bu nedenle kullanmamanız için bir neden yoktur.

Eski cevap takip eder, ancak modası geçmiş gibi sakının.


Gelecekte² Google çalışanları için, Yahel'in Quasimondo'nun algoritması algoritmasından, ancak NDK kullanarak taşıdığım bir algoritma. Elbette Yahel'in cevabına dayanıyor. Ama bu yerel C kodu çalıştırıyor, bu yüzden daha hızlı. Çok daha hızlı. 40 kat daha hızlı.

NDK kullanmanın Android'de tüm görüntü manipülasyonunun nasıl yapılması gerektiğini buluyorum ... ilk başta uygulamak biraz can sıkıcı ( burada JNI ve NDK kullanımı hakkında harika bir öğretici okuyun ), ancak çok daha iyi ve gerçek zamanlıya yakın birçok şey.

Referans olarak, Yahel'in Java işlevini kullanarak, 480x532 piksel görüntüyü 10 bulanıklık yarıçapıyla bulanıklaştırmak 10 saniye sürdü. Ancak yerel C sürümünü kullanarak 250 ms sürdü. Ve hala daha da optimize edilebilir eminim ... Sadece java kodu aptal bir dönüşüm yaptım, muhtemelen kısaltılabilir bazı manipülasyonlar var, her şeyi yeniden düzenlemek için çok fazla zaman harcamak istemiyordu.

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

Daha sonra bu şekilde kullanın (com.insert.your.package.ClassName ve yukarıdaki kodun belirttiği gibi functionToBlur adlı yerel bir işlevi göz önünde bulundurarak):

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

Bir RGB_8888 bitmap bekliyor!

RGB_565 bitmap kullanmak için, parametreyi (yuck) geçmeden önce dönüştürülmüş bir kopya oluşturun veya işlevi rgb565yerine yeni bir tür kullanacak şekilde değiştirin rgba:

typedef struct {
    uint16_t byte0;
} rgb565;

Sorun sen okuyamaz bunu yaparsan olduğunu .red, .greenve .blueartık pikselin, sen düzgün yaa byte okumak gerekir. Daha önce ihtiyacım olduğunda bunu yaptım:

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

Ama muhtemelen bunu yapmanın daha az aptalca bir yolu var. Korkarım, düşük seviyeli bir C kodlayıcı değilim.


Teşekkürler, bana çok yardımcı oldu :)
Dmitry Zaytsev

18
AMA çok fazla bellek gerektirir . Bellek tüketimi değişimi türünü azaltmak için r[wh], g[wh]ve b[wh]için uint8_t.
Dmitry Zaytsev

Android.mk dosyanızın neye benzediğini gösterebilir misinizpastebin.com
CQM

1
Android SDK 17+ üzerinde çalışan bir Gauss Bulanıklığı örneği için buraya bakın: stackoverflow.com/questions/14988990/android-fast-bitmap-blur
Martin Marconcini

2
RenderScript ayrıca Android 2.2 ve sonraki sürümleri için destek kütüphanesinin bir parçası olarak da mevcuttur, bu yüzden artık her yerde kullanmamanın bir nedeni yoktur: android-developers.blogspot.com/2013/09/…
zeh 27:13

14

Bu kod benim için mükemmel

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

}

Görüntüyü bulanıklaştırmanın en basit yolu (y)
VAdaihiep

12

Artık hızlı bulanıklaştırmak için RenderScript kütüphanesinden ScriptIntrinsicBlur'u kullanabilirsiniz . İşte RenderScript API erişmek için nasıl. Views ve Bitmap'leri bulanıklaştırmak için yaptığım bir sınıf:

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
Renderscript bağlamı blur yönteminde oluşturulmamalı, statik olarak yönetilmeli veya yönteme verilmelidir. (performansı
önemsiyorsanız

1
Bunun kullanımına bir örnek verebilir misiniz? Kullanmaya çalıştığımda aşağıdaki hatayı alıyorum: java.lang.IllegalArgumentException: genişlik ve yükseklik> 0
Donal Rafferty

10

Bu benim için iyi çalıştı: Android RenderScript ile Görüntüleri Verimli Bir Şekilde Bulanıklaştırma

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

Oluşturduğunuz RenderScript nesnesini önbelleğe alırsanız, bu daha da iyi / hızlı olur. Bir görüntüyü her bulanıklaştırmak istediğinizde yeni bir örnek oluşturmak, gereksiz ek yükü (Java nesnesi oluşturma / imha etme) ekler.
Stephen Hines


4

Bu, ScriptIntrinsicBlurdaha sert bir gauss bulanıklığı elde etmek için yarıçapı arttırması gereken tüm insanlar içindir .

Yarıçapı 25'ten fazla koymak yerine, görüntüyü küçültebilir ve aynı sonucu elde edebilirsiniz. Adlı bir sınıf yazdımGaussianBlur . Aşağıda nasıl kullanılacağını ve tüm sınıf uygulamasını görebilirsiniz.

Kullanımı:

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

Sınıf:

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

hayır daha sonra bunun yerine :( bir blured görüntünün bloklu görüntüsünü alır büyütmek için resmi ölçeklendirme eğer
loki

4

@Yahel kod için teşekkürler. Alfa kanalı bulanıklaştırma desteği ile aynı yöntemi göndermek, düzgün çalışmamın biraz zaman almasını sağladı, böylece birinin zamanını kurtarabilir:

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

hala cihazlarda 'indeks aralık dışında'> orijinal kaynak olarak hdpi
Gabriel Ferreira

4

Bunu daha önce kullandım ..

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

NDK yaklaşımını seçen gelecekteki Google çalışanları için güvenilir güvenilir yığın blöf algoritması buluyorum. Burada SSE'ye dayanmayan C ++ uygulaması buldum - http://www.antigrain.com/__code/include/agg_blur.h.html#stack_blur_rgba32 gibi statik tablolar kullanarak bazı optimizasyonlar içeriyor:

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

Çok çekirdekli sistemler için stackblur algoritmasında değişiklik yaptım - burada bulunabilir http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/ Gittikçe daha fazla cihaz 4 çekirdeğe sahip olduğundan - optimizasyonlar 4 kat hız avantajı.


1

Nicolas POMEPUY tavsiyesi. Bu bağlantının faydalı olacağını düşünüyorum: Android tasarımı için bulanıklık efekti

Github'da örnek proje

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

Bu bağlantı soruyu cevaplayabilse de, cevabın temel kısımlarını buraya eklemek ve bağlantıyı referans olarak sağlamak daha iyidir. Bağlantı verilen sayfa değişirse, yalnızca bağlantı yanıtları geçersiz olabilir.
Amal Murali

1
Amal Murali, haklısın. Şimdi yazımı değiştir. İyi, sadece aşağı değil, aynı zamanda yorum da yapıyorsunuz.
Yura Shinkarev

1

RenderScript bulanıklığını yukarıda belirtildiği gibi farklı yanıtlarda uygulamaya çalıştık. V8 RenderScript sürümünü kullanmakla sınırlı kaldık ve bu bize çok fazla sorun yarattı.

  • Samsung S3, renderscript'i kullanmaya çalıştığımızda rastgele çöktü
  • Diğer cihazlar (farklı API'lerde) rastgele farklı renk sorunları gösterdi

Yavaş ve ayrı bir iş parçacığında ve mümkünse kullanımdan önce yapılması gereken ve bu nedenle kalıcı olan yalnızca Java içeren kirli sürümümüzü paylaşmak istiyorum.

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

Bu çözüm mükemmel olmaktan uzaktır, ancak aynı görüntünün oldukça şeffaf bir versiyonunu zar zor şeffaf "keskin" bir versiyonun üzerine çekmesi gerçeğine dayanarak makul bir bulanıklık efekti yaratır. Alfa başlangıç ​​noktasına olan mesafeye bağlıdır.

İhtiyaçlarınıza göre bazı “sihirli sayılar” ayarlayabilirsiniz. RenderScript'in v8 destek sürümü ile ilgili sorunları olan herkes için bu "çözümü" paylaşmak istedim.


Ayrıca bazı eski armeabi cihazlarında RenderScript ile ilgili bir sorun yaşıyorum, ancak çözümünüz çok fazla bellek tüketiyor.
AsafK

0

X86 yonga kümelerinde Renderscript destek kitaplığıyla ilgili hala sorun yaşayanlar için lütfen bu gönderiyi kitaplığın yaratıcısı tarafından inceleyin. Hazırladığı düzeltme, bir şekilde Yapı Araçları v20.0.0'a bir şey yapmadı gibi görünüyor, bu yüzden manuel olarak düzeltmek için dosyalar ve nasıl yapılacağına dair kısa bir açıklama sağlıyor.

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

Azalan kontrast, parlaklık ve doygunluğun biraz bulanık görüntüleri daha güzel hale getirdiğini gördüm, bu yüzden yığın taşmasından çeşitli yöntemleri birleştirdim ve bulanık görüntülerle, bulanık görüntülerin parlaklığını, doygunluğunu, kontrastını ve boyutunu değiştiren bu Blur Sınıfını yaptım . Ayrıca görüntüleri çekilebilirden bitmap'e veya tersine dönüştürebilir.


0

İ / o 2019'da aşağıdaki çözüm sunuldu:

/**
 * 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()
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.