Android:快速位图模糊?

时间:2013-02-20 20:10:05

标签: android image-processing blur convolution

过去三天我一直在寻找一种内置的,硬件加速的方法来使用android来模拟位图。我偶然发现了某些解决方法,比如缩小位图并再次缩放,但这种方法产生的质量低,不适合我的图像识别要求。我还读到使用着色器或JNI实现卷积是一个很好的方法,但我不能相信Android框架中没有内置的解决方案用于这个非常常见的目的。目前我最终在Java中使用自编写的卷积实现,但它的速度非常慢。我的问题是:

  • Android框架中是否确实没有内置解决方案
  • 如果没有:在实现和维护的合理复杂性的情况下,加速卷积的最有效方法是什么?我们应该使用JNI,着色器还是完全不同的东西?

2 个答案:

答案 0 :(得分:70)

我终于找到了合适的解决方案:

  • RenderScript允许实现大量计算,这些计算可以透明地扩展到执行设备上可用的所有核心。我得出的结论是,在性能和实现复杂性的合理平衡方面,这是一种比JNI或着色器更好的方法。
  • 自API级别17以来,API中提供了ScriptIntrinsicBlur类。这正是我一直在寻找的,即高级,硬件加速的高斯模糊实现。
  • ScriptIntrinsicBlur现在是支持Froyo及以上版本(API> 8)的android支持库(v8)的一部分。 support RenderScript library上的android开发者博客帖子提供了一些关于如何使用它的基本技巧。

但是,ScriptIntrinsicBlur类的文档非常少见,我花了一些时间来确定正确的调用参数。对于模拟名为ARGB_8888的普通photo类型位图,这里它们是:

final RenderScript rs = RenderScript.create( myAndroidContext );
final Allocation input = Allocation.createFromBitmap( rs, photo, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT );
final Allocation output = Allocation.createTyped( rs, input.getType() );
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create( rs, Element.U8_4( rs ) );
script.setRadius( myBlurRadius /* e.g. 3.f */ );
script.setInput( input );
script.forEach( output );
output.copyTo( photo );

答案 1 :(得分:12)

最苛刻的要求可能是实时模糊,这意味着当视图发生变化时,您会模糊不清。在这种情况下,模糊不应超过10秒左右(使一些游戏室达到16ms / 60fps)看起来平滑。即使在不那么高端的设备(galaxy s3甚至更慢)上,也可以通过正确的设置实现这种效果。

以下是如何以不断下降的重要性提高绩效:

  1. 使用缩小尺寸的图片: 这会使像素大幅度模糊。当你想要一个真实的模糊图像时它也适合你。此外,图像加载和内存消耗也大幅降低。

  2. 使用Renderscript ScriptIntrinsicBlur - 自2014年起,Android中可能没有更好/更快的解决方案。我经常看到的一个错误是Renderscript上下文不会被重用,而是每次使用模糊算法时都会创建。请注意,RenderScript.create(this);在Nexus 5上需要大约20毫秒,因此您要避免这种情况。

  3. 重用位图:不要创建不必要的实例并始终使用相同的实例。当你需要非常快速的模糊时,垃圾收集起着重要的作用(收集一些位图需要10-20毫秒)。还可以裁剪和模糊你所需要的东西。

  4. 对于实时模糊,可能是因为上下文切换,它不可能在另一个线程中模糊(即使使用线程池),只有主线程足够快以保持视图及时更新,线程我看到了100-300ms的滞后

  5. 有关更多提示,请参阅此处的其他帖子https://stackoverflow.com/a/23119957/774398

    顺便说一句。我在这款应用中做了一个简单的实时模糊:githubPlaystore