33

在过去的三天里,我一直在寻找一种内置的、硬件加速的使用 android 模糊位图的方法。我偶然发现了某些变通方法,例如缩小位图并再次放大它,但这种方法产生的结果质量很低,不适合我的图像识别要求。我还读到使用着色器或 JNI 实现卷积是一个不错的方法,但我不敢相信 Android 框架中没有针对这个非常常见的目的的内置解决方案。目前我已经用 Java 编写了一个自写的卷积实现,但速度慢得令人尴尬。我的问题是:

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

2 回答 2

73

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

  • RenderScript允许实现大量计算,这些计算透明地扩展到执行设备上可用的所有内核。我得出的结论是,就性能和实现复杂性的合理平衡而言,这是比 JNI 或着色器更好的方法。
  • 从 API 级别 17 开始,API 提供了ScriptIntrinsicBlur类。这正是我一直在寻找的,即高级的、硬件加速的高斯模糊实现。
  • ScriptIntrinsicBlur现在是支持 Froyo 及更高版本 (API>8) 的 android 支持库 (v8) 的一部分。支持 RenderScript 库的 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 );
于 2013-02-20T20:10:04.577 回答
13

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

以下是如何提高重要性递减的性能:

  1. 使用缩小的图像:这会极大地减少像素模糊。当您想要真正的模糊图像时,它也适用于您。图像加载和内存消耗也大大降低。

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

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

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

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

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

于 2014-04-27T22:42:42.393 回答