Android SDK 快速位图模糊

我想分享我的经验与 \n
我注意到“ n”的作用是 -

puts "\n\n" // to provide 2 new lines

但不是

p "\n\n"

目前在我正在开发的一个 Android 应用程序中,我通过循环处理图像的像素来模糊它。这在640x480的图像上大约需要30秒。

还有 把 '\n\n'
没用的。

当我在 Android 市场浏览应用程序时,我遇到了一个包含模糊特性的应用程序,它们的模糊速度非常快(大约5秒) ,所以它们一定是使用了不同的模糊方法。

希望会为你工作! !

有人知道除了循环遍历像素之外更快的方法吗?

153440 次浏览
结果:

puts "Coach says: #{coach_answer(user_input)}\n"

但这个确实做到了:

puts "Coach says: #{coach_answer(user_input)}"
print "\n"

一般来说,这是因为

    遇到 ArrayIndexOutOfBoundsException 问题的用户更新: @anthonycr 在评论中提供了以下信息:

  1. 游戏正在优化他们需要渲染什么,并且
  2. 我通过用 StrictMath.abs 或其他什么东西替换 Math.abs 发现了这一点

  3. 他们特别利用你的硬件。
Abs 实现时,不会发生崩溃。

/**
* Stack Blur v1.0 from
* http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
* Java Author: Mario Klingemann <mario at quasimondo.com>
* http://incubator.quasimondo.com
*
* created Feburary 29, 2004
* Android port : Yahel Bouaziz <yahel at kayenko.com>
* http://www.kayenko.com
* ported april 5th, 2012
*
* This is a compromise between Gaussian Blur and Box blur
* It creates much better looking blurs than Box Blur, but is
* 7x faster than my Gaussian Blur implementation.
*
* I called it Stack Blur because this describes best how this
* filter works internally: it creates a kind of moving stack
* of colors whilst scanning through the image. Thereby it
* just has to add one new block of color to the right side
* of the stack and remove the leftmost color. The remaining
* colors on the topmost layer of the stack are either added on
* or reduced by one, depending on if they are on the right or
* on the left side of the stack.
*
* If you are using this algorithm in your code please add
* the following line:
* Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
*/


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


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


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


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


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


int[] pix = new int[w * h];
Log.e("pix", w + " " + h + " " + pix.length);
bitmap.getPixels(pix, 0, w, 0, 0, w, h);


int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;


int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int vmin[] = new int[Math.max(w, h)];


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


yw = yi = 0;


int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;


for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;


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


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


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


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


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


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


sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);


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


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


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


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


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


yi++;
}
yw += w;
}
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;


sir = stack[i + radius];


sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];


rbs = r1 - Math.abs(i);


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


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


if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
pix[yi] = ( 0xff000000 & pix[yi] ) | ( dv[rsum] << 16 ) | ( dv[gsum] << 8 ) | dv[bsum];


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


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


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


if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];


sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];


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


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


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


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


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


yi += w;
}
}


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


return (bitmap);
}

但是可能有一些不那么愚蠢的方法来做到这一点。恐怕我不是一个低级别的 C 程序员。

因为一些原因

    对于未来的谷歌谁选择 NDK 方法-我发现可靠的提到堆栈模糊算法。我发现 C + + 的实现并不依赖于 SSE-http://www.antigrain.com/__code/include/agg_blur.h.html#stack_blur_rgba32包含一些使用静态表的优化,比如:

    static unsigned short const stackblur_mul[255] =
    {
    512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,
    454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,
    482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,
    437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,
    497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,
    320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,
    446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,
    329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,
    505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,
    399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,
    324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,
    268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,
    451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,
    385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,
    332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,
    289,287,285,282,280,278,275,273,271,269,267,265,263,261,259
    };
    
    
    static unsigned char const stackblur_shr[255] =
    {
    9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
    17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
    20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
    23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
    23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
    };
    
  • 3D 游戏引擎高度优化
  • 我修改了多核系统的堆栈模糊算法-它可以在这里找到 < a href = “ http://vitiy.info/stackdim-method-multi-threaded-Fuzzy-for-cpp/”rel = “ nofollow”> http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/

  • 大部分工作是由你的显示卡完成的
  • 随着越来越多的设备有4个核心-优化给予4倍的速度优势。

  • 50% 嗯,让我猜猜你有一个双核心,只有一个核心使用; -)
  • 使用这里提到的渲染脚本 http://blog.neteril.org/blog/2013/08/12/blurring-images-on-android/

    编辑: 给出一些数字

    2.8 Ghz Athlon-64配备 NV-6800图形处理器,测试结果如下:

    • CPU: 72.78 Mflops
    • 您现在可以从渲染脚本库中使用 脚本内在模糊来快速模糊。给你是如何访问渲染脚本 API。下面是我编写的模糊视图和位图的类:

      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;
      }
      }
      
  • GPU: 2440.32 Mflops
  • Jelly _ BEAN _ MR1)

    尼古拉斯 · 波梅普的建议。我认为这个链接将是有帮助的: < strong > Android 设计的模糊效果

    私有静态位图快速模糊16(位图源,半径,上下文 ctx){

    样品项目在 Github

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

    任何答案的核心都应该是这样的——3D 引擎执行的转换大部分是在加法和乘法(线性代数)中指定的(没有分支或跳跃) ,绘制一个单一框架的操作通常是在多个这样的加法任务可以并行完成的情况下指定的。GPU 内核是非常好的加法多核,它们有几十或几百个加法多核。

    基本上,他解释说,他预先模糊了一些框架与不同的模糊范围,并使用它们作为关键帧的动画,看起来真的很顺利。

    Diagram where Nurik exaplains his approach

    你可以根据自己的需要调整一些“神奇的数字”。 我只是想把这个“解决方案”分享给那些对渲染脚本的 v8支持版本有疑问的人。

    有时候一个场景可能比表面上看起来更有意思。例如,一个具有数千顶点的旋转茶壶、环境映射、凹凸映射以及其他复杂的像素着色器同时呈现,这就相当于大量的处理工作。很多时候,这些茶壶演示只是为了展示某种特殊效果。当绝对性能不是目标时,他们也许并不总是能最好地利用 GPU。

    这个代码对我来说太完美了

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

    对于那些仍然在 x86芯片组上有 Renderscript 支持库问题的人,请看一下这个库的创建者的文章。看起来他准备的修复程序没有以某种方式进入 Build Tools v20.0.0,所以他提供了手动修复的文件,并简要说明了如何进行修复。

    Https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=id%20type%20status%20owner%20summary%20stars&groupby=&sort=&id=71347

    不需要把半径放大到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;
    }
    }
    

    第一点是,DX 演示主要是一个教学辅助工具,所以这样做是为了清晰,而不是执行速度。

    来自 Mario Viviani 的博客一个人可以使用这个来自17个 Android 版本的解决方案:

    Https://plus.google.com/+marioviviani/posts/fhuzykji9zz

    或者

    这是一个非常大的主题,但游戏开发主要是关于理解您的数据和您的执行路径到一个近乎病态的程度。

      Https://gist.github.com/mariuxtheone/903c35b4927c0df18cf8

  • 您的代码是围绕两件事情设计的——您的数据和您的目标硬件。
  • 这对我来说很有效: 如何使用 Android 渲染脚本有效地模糊图像

    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;
    }
    }
    
  • 最快的代码是永远不会执行的代码——将数据分批排序,只对需要执行的数据执行昂贵的操作
  • 谢谢@Yahel 的密码。

  • 如何存储您的数据是关键-连续访问的目标,这使您能够批处理的高速度。
  • 尽可能平行化所有东西
  • 张贴相同的方法与 阿尔法通道模糊的支持,因为它花了我一些时间,使其正确工作,所以它可以节省某人的时间:

    /**
    * Stack Blur v1.0 from
    * http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
    * Java Author: Mario Klingemann <mario at quasimondo.com>
    * http://incubator.quasimondo.com
    * <p/>
    * created Feburary 29, 2004
    * Android port : Yahel Bouaziz <yahel at kayenko.com>
    * http://www.kayenko.com
    * ported april 5th, 2012
    * <p/>
    * This is a compromise between Gaussian Blur and Box blur
    * It creates much better looking blurs than Box Blur, but is
    * 7x faster than my Gaussian Blur implementation.
    * <p/>
    * I called it Stack Blur because this describes best how this
    * filter works internally: it creates a kind of moving stack
    * of colors whilst scanning through the image. Thereby it
    * just has to add one new block of color to the right side
    * of the stack and remove the leftmost color. The remaining
    * colors on the topmost layer of the stack are either added on
    * or reduced by one, depending on if they are on the right or
    * on the left side of the stack.
    * <p/>
    * If you are using this algorithm in your code please add
    * the following line:
    * Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
    */
    
    
    public static Bitmap fastblur(Bitmap sentBitmap, float scale, int radius) {
    
    
    int width = Math.round(sentBitmap.getWidth() * scale);
    int height = Math.round(sentBitmap.getHeight() * scale);
    sentBitmap = Bitmap.createScaledBitmap(sentBitmap, width, height, false);
    
    
    Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
    
    
    if (radius < 1) {
    return (null);
    }
    
    
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();
    
    
    int[] pix = new int[w * h];
    Log.e("pix", w + " " + h + " " + pix.length);
    bitmap.getPixels(pix, 0, w, 0, 0, w, h);
    
    
    int wm = w - 1;
    int hm = h - 1;
    int wh = w * h;
    int div = radius + radius + 1;
    
    
    int r[] = new int[wh];
    int g[] = new int[wh];
    int b[] = new int[wh];
    int a[] = new int[wh];
    int rsum, gsum, bsum, asum, x, y, i, p, yp, yi, yw;
    int vmin[] = new int[Math.max(w, h)];
    
    
    int divsum = (div + 1) >> 1;
    divsum *= divsum;
    int dv[] = new int[256 * divsum];
    for (i = 0; i < 256 * divsum; i++) {
    dv[i] = (i / divsum);
    }
    
    
    yw = yi = 0;
    
    
    int[][] stack = new int[div][4];
    int stackpointer;
    int stackstart;
    int[] sir;
    int rbs;
    int r1 = radius + 1;
    int routsum, goutsum, boutsum, aoutsum;
    int rinsum, ginsum, binsum, ainsum;
    
    
    for (y = 0; y < h; y++) {
    rinsum = ginsum = binsum = ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0;
    for (i = -radius; i <= radius; i++) {
    p = pix[yi + Math.min(wm, Math.max(i, 0))];
    sir = stack[i + radius];
    sir[0] = (p & 0xff0000) >> 16;
    sir[1] = (p & 0x00ff00) >> 8;
    sir[2] = (p & 0x0000ff);
    sir[3] = 0xff & (p >> 24);
    
    
    rbs = r1 - Math.abs(i);
    rsum += sir[0] * rbs;
    gsum += sir[1] * rbs;
    bsum += sir[2] * rbs;
    asum += sir[3] * rbs;
    if (i > 0) {
    rinsum += sir[0];
    ginsum += sir[1];
    binsum += sir[2];
    ainsum += sir[3];
    } else {
    routsum += sir[0];
    goutsum += sir[1];
    boutsum += sir[2];
    aoutsum += sir[3];
    }
    }
    stackpointer = radius;
    
    
    for (x = 0; x < w; x++) {
    
    
    r[yi] = dv[rsum];
    g[yi] = dv[gsum];
    b[yi] = dv[bsum];
    a[yi] = dv[asum];
    
    
    rsum -= routsum;
    gsum -= goutsum;
    bsum -= boutsum;
    asum -= aoutsum;
    
    
    stackstart = stackpointer - radius + div;
    sir = stack[stackstart % div];
    
    
    routsum -= sir[0];
    goutsum -= sir[1];
    boutsum -= sir[2];
    aoutsum -= sir[3];
    
    
    if (y == 0) {
    vmin[x] = Math.min(x + radius + 1, wm);
    }
    p = pix[yw + vmin[x]];
    
    
    sir[0] = (p & 0xff0000) >> 16;
    sir[1] = (p & 0x00ff00) >> 8;
    sir[2] = (p & 0x0000ff);
    sir[3] = 0xff & (p >> 24);
    
    
    rinsum += sir[0];
    ginsum += sir[1];
    binsum += sir[2];
    ainsum += sir[3];
    
    
    rsum += rinsum;
    gsum += ginsum;
    bsum += binsum;
    asum += ainsum;
    
    
    stackpointer = (stackpointer + 1) % div;
    sir = stack[(stackpointer) % div];
    
    
    routsum += sir[0];
    goutsum += sir[1];
    boutsum += sir[2];
    aoutsum += sir[3];
    
    
    rinsum -= sir[0];
    ginsum -= sir[1];
    binsum -= sir[2];
    ainsum -= sir[3];
    
    
    yi++;
    }
    yw += w;
    }
    for (x = 0; x < w; x++) {
    rinsum = ginsum = binsum = ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0;
    yp = -radius * w;
    for (i = -radius; i <= radius; i++) {
    yi = Math.max(0, yp) + x;
    
    
    sir = stack[i + radius];
    
    
    sir[0] = r[yi];
    sir[1] = g[yi];
    sir[2] = b[yi];
    sir[3] = a[yi];
    
    
    rbs = r1 - Math.abs(i);
    
    
    rsum += r[yi] * rbs;
    gsum += g[yi] * rbs;
    bsum += b[yi] * rbs;
    asum += a[yi] * rbs;
    
    
    if (i > 0) {
    rinsum += sir[0];
    ginsum += sir[1];
    binsum += sir[2];
    ainsum += sir[3];
    } else {
    routsum += sir[0];
    goutsum += sir[1];
    boutsum += sir[2];
    aoutsum += sir[3];
    }
    
    
    if (i < hm) {
    yp += w;
    }
    }
    yi = x;
    stackpointer = radius;
    for (y = 0; y < h; y++) {
    pix[yi] = (dv[asum] << 24) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
    
    
    rsum -= routsum;
    gsum -= goutsum;
    bsum -= boutsum;
    asum -= aoutsum;
    
    
    stackstart = stackpointer - radius + div;
    sir = stack[stackstart % div];
    
    
    routsum -= sir[0];
    goutsum -= sir[1];
    boutsum -= sir[2];
    aoutsum -= sir[3];
    
    
    if (x == 0) {
    vmin[y] = Math.min(y + r1, hm) * w;
    }
    p = x + vmin[y];
    
    
    
    
    sir[0] = r[p];
    sir[1] = g[p];
    sir[2] = b[p];
    sir[3] = a[p];
    
    
    rinsum += sir[0];
    ginsum += sir[1];
    binsum += sir[2];
    ainsum += sir[3];
    
    
    rsum += rinsum;
    gsum += ginsum;
    bsum += binsum;
    asum += ainsum;
    
    
    stackpointer = (stackpointer + 1) % div;
    sir = stack[stackpointer];
    
    
    routsum += sir[0];
    goutsum += sir[1];
    boutsum += sir[2];
    aoutsum += sir[3];
    
    
    rinsum -= sir[0];
    ginsum -= sir[1];
    binsum -= sir[2];
    ainsum -= sir[3];
    
    
    yi += w;
    }
    }
    
    
    Log.e("pix", w + " " + h + " " + pix.length);
    bitmap.setPixels(pix, 0, w, 0, 0, w, h);
    
    
    return (bitmap);
    }
    
  • 现代 CPU 速度很快,现代 RAM 速度很慢,缓存丢失是致命的。
  • 我以前用过这个。

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

    这里是一个使用渲染脚本的实时模糊覆盖图,看起来足够快了。

  • 尽可能多地向 GPU 推送数据——它有快速的本地存储器,因此可以快速浏览数据,但是你需要通过正确组织数据来帮助它。
  • Https://github.com/mmin18/realtimeblurview

    我发现减少 对比度、亮度和饱和度一点点使模糊图像更加美观,所以我结合各种方法从堆栈溢出,使这个 模糊类处理模糊图像,改变亮度,饱和度,对比度和大小的模糊图像。它还可以将图像从可绘制转换为位图,反之亦然。

    考虑到更多的反射光的影响,等等,但它是计算昂贵的-这是一个射线追踪技术。

    3D 游戏很擅长欺骗你的眼睛。例如,有一种叫做屏幕空间环境光屏蔽(SSAO)的技术,它可以通过遮挡场景中接近表面不连续性的部分来给人一种更真实的感觉。如果你看看墙的角落,你会发现在大多数情况下,它们看起来比中心稍微暗一些。

    这只是一个例子。实时计算机图形学有数百种算法,它们基本上都是基于良好的近似值,通常会做出很多假设。例如,空间排序必须非常仔细地选择取决于速度,典型的相机位置以及场景几何形状的变化量。

    在相当精确的模拟基础上,利用辐射度可以达到非常相同的效果。辐射度还将考虑更多的反射光的影响,等等,但它是计算昂贵-这是一种射线追踪技术。

    这只是一个例子。实时计算机图形学有数百种算法,它们基本上都是基于良好的近似值,通常会做出很多假设。例如,空间排序必须非常仔细地选择取决于速度,典型的相机位置以及场景几何形状的变化量。

    这些“优化”是 巨大-你可以有效地实现一个算法并使其运行速度提高10倍,但是选择一个产生类似结果的智能算法(“欺骗”)可以使你从 O (N ^ 4)到 O (log (N))。

    这些“优化”是 巨大-你可以有效地实现一个算法并使其运行速度提高10倍,但是选择一个产生类似结果的智能算法(“欺骗”)可以使你从 O (N ^ 4)到 O (log (N))。

    优化实际的执行是什么使游戏更有效率,但这只是一个线性优化。

    1. 场景管理。 kd 树,障碍物剔除,bsps,等级边界框,部分可见性集。
    2. 关于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()
      }
      }