android图片的高斯模糊效果

本文详细介绍在安卓中实现图片高斯模糊效果的两种技术:RenderScript和fastBlur。RenderScript在C/C++层处理,性能较好,但需兼容包支持;fastBlur在Java层处理,效率较低。文章提供代码示例并提出优化方案,如先缩小图片再模糊。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先在安卓中对于图片的高斯模糊效果处理主要采用了RenderScript和fastBlur两种技术。

1,采用RenderScript

 

private static Bitmap renderScriptBlur(Context context, Bitmap source, int radius){
        Bitmap inputBmp = source;
        //1
        RenderScript renderScript = RenderScript.create(context);
        
        //2
        final Allocation input = Allocation.createFromBitmap(renderScript,inputBmp);
        final Allocation output = Allocation.createTyped(renderScript,input.getType());
        //3
        ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
        //4
        scriptIntrinsicBlur.setInput(input);
        //5
        scriptIntrinsicBlur.setRadius(radius);
        //6
        scriptIntrinsicBlur.forEach(output);
        //7
        output.copyTo(inputBmp);
        //8
        renderScript.destroy();
        return inputBmp;
    }

 此方法是在c/c++层做处理,因此性能比较好,但是有个局限就是ScriptintrisicBlur类在API 17以上才能使用,要向下兼容的话需要加入support.v8.renderscript兼容包,兼容到API 9 ,并且在app的build.gradle中添加如下两条renderScript的信息

defaultConfig { 
    minSdkVersion 9 
    targetSdkVersion 19 
    // 使用support.v8.renderscript 
    renderscriptTargetApi 18 
    renderscriptSupportModeEnabled true 
}

缺点:引入兼容包增大了apk的体积

ps:此类方式下RenderScript效率仍然是达不到16ms/桢,还有进一步的空间

优化方案: 采用了先缩小图片,再去模糊的方案,最后再放大图片

更改后的代码(注意此方法返回的bitmap时缩小的图片):

private static Bitmap renderScriptBlur(Context context, Bitmap source, int radius,float scale){
        //1
        int width = Math.round(source.getWidth * scale);
        int height = Math.round(source.getHeight() * scale);

        Bitmap inputBmp = Bitmap.createScaledBitmap(source,width,height,false);
        //2
        RenderScript renderScript = RenderScript.create(context);
        
        //3
        final Allocation input = Allocation.createFromBitmap(renderScript,inputBmp);
        final Allocation output = Allocation.createTyped(renderScript,input.getType());
        //4
        ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
        //5
        scriptIntrinsicBlur.setInput(input);
        //6
        scriptIntrinsicBlur.setRadius(radius);
        //7
        scriptIntrinsicBlur.forEach(output);
        //8
        output.copyTo(inputBmp);
        //9
        renderScript.destroy();
        return inputBmp;
    }

2,fastBlur

直接在Java层做处理,对每个像素点应用高斯模糊计算,并合成最终的一张bitmap

缺点:效率慢,速度比RenderScript慢了近十倍,会有导致OOM的可能

优化方案:采用了先缩小图片,再去模糊的方案,最后再放大图片

整个代码(注意此方法返回的bitmap时缩小的图片):

private static Bitmap fastBlur(Bitmap sentBitmap, float scale, int radius) {
        int width = Math.round((float)sentBitmap.getWidth() * scale);
        int height = Math.round((float)sentBitmap.getHeight() * scale);
        sentBitmap = Bitmap.createScaledBitmap(sentBitmap, width, height, false);
        Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
        if(radius < 1) {
            return null;
        } else {
            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[] vmin = new int[Math.max(w, h)];
            int divsum = div + 1 >> 1;
            divsum *= divsum;
            int[] dv = new int[256 * divsum];

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

            int yi = 0;
            int yw = 0;
            int[][] stack = new int[div][3];
            int r1 = radius + 1;

            int rsum;
            int gsum;
            int bsum;
            int x;
            int y;
            int p;
            int stackpointer;
            int stackstart;
            int[] sir;
            int rbs;
            int routsum;
            int goutsum;
            int boutsum;
            int rinsum;
            int ginsum;
            int binsum;
            for(y = 0; y < h; ++y) {
                bsum = 0;
                gsum = 0;
                rsum = 0;
                boutsum = 0;
                goutsum = 0;
                routsum = 0;
                binsum = 0;
                ginsum = 0;
                rinsum = 0;

                for(i = -radius; i <= radius; ++i) {
                    p = pix[yi + Math.min(wm, Math.max(i, 0))];
                    sir = stack[i + radius];
                    sir[0] = (p & 16711680) >> 16;
                    sir[1] = (p & '\uff00') >> 8;
                    sir[2] = p & 255;
                    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 & 16711680) >> 16;
                    sir[1] = (p & '\uff00') >> 8;
                    sir[2] = p & 255;
                    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) {
                bsum = 0;
                gsum = 0;
                rsum = 0;
                boutsum = 0;
                goutsum = 0;
                routsum = 0;
                binsum = 0;
                ginsum = 0;
                rinsum = 0;
                int yp = -radius * w;

                for(i = -radius; i <= radius; ++i) {
                    yi = Math.max(0, yp) + x;
                    sir = stack[i + radius];
                    sir[0] = r[yi];
                    sir[1] = g[yi];
                    sir[2] = b[yi];
                    rbs = r1 - Math.abs(i);
                    rsum += r[yi] * rbs;
                    gsum += g[yi] * rbs;
                    bsum += b[yi] * rbs;
                    if(i > 0) {
                        rinsum += sir[0];
                        ginsum += sir[1];
                        binsum += sir[2];
                    } else {
                        routsum += sir[0];
                        goutsum += sir[1];
                        boutsum += sir[2];
                    }

                    if(i < hm) {
                        yp += w;
                    }
                }

                yi = x;
                stackpointer = radius;

                for(y = 0; y < h; ++y) {
                    pix[yi] = -16777216 & 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;
        }
    }

github地址:https://github.com/MelvinCen/ImageBlur

本文参考学习于简书,原作者写的更加详细一些https://www.jianshu.com/p/02da487a2f43  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值