【问题标题】:Android: fast bitmap blur?Android:快速位图模糊?
【发布时间】:2013-02-05 23:50:57
【问题描述】:

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

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

【问题讨论】:

    标签: android image-processing blur convolution


    【解决方案1】:

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

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

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

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

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

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

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

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

    【讨论】:

    • 关于#2,我看不出它有这么好的模糊质量(见这里:stackoverflow.com/q/36447630/878126)。另外,您是否真的建议 Renderscript 对象将在整个应用程序生命周期中保留,而无需对其调用“destroy()”?
    • 嗨,我想你已经在你的帖子中发现了质量差的错误(我想说我无法重现你的差输出)。对于第二点:如果你做了模糊处理,当然不会破坏上下文。请记住,创建上下文是昂贵的
    • 质量不好 - 我不确定原因(因为我使用了其他示例和教程代码),但我使用了“createTyped”,现在它可以工作了。如果您可以在那里写下我遇到这些问题的原因,那就太好了。关于“破坏上下文”,我说的是 RenderScript.create。如果我在应用程序的很多地方模糊了图像,那么永远不要破坏它应该没问题,对吧?另外,我使用哪个上下文作为它的论点有关系吗?
    • 我不熟悉渲染脚本的详细信息,请其中一位来回答您的问题(他们在 google 渲染脚本团队工作):stackoverflow.com/users/1988713/tim-murraystackoverflow.com/users/1819933/r-jason-sams。我想您使用哪种上下文并不重要(我认为它仅用于物流,例如获取渲染脚本文件的定义文件夹)。对于 Renderscript 生命周期:在您链接的应用程序中,我确实在 onPause() 中销毁了上下文。但这取决于您的用例,如果您只是模糊 1 张图像并将其放入缓存中,您可以立即销毁
    • 好的,谢谢。但是,如果我什至给它一个活动作为参数,它会不会是内存泄漏,但即使在活动被破坏后,Renderscript 对象的实例仍然存在?
    【解决方案2】:

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

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

    然而,ScriptIntrinsicBlur 类的文档非常少见,我花了更多时间找出正确的调用参数。用于模糊名为photo 的普通ARGB_8888 类型位图,它们是:

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

    【讨论】:

    • @thV0ID :很好的答案。有什么方法可以使它向后兼容,也可以在 ICS 中工作?
    • @BhaveshPatadiya:您可以使用 RenderScript 实现快速卷积并使用高斯内核。可以在此处找到使用 RenderScript 实现卷积的示例:stackoverflow.com/a/10257994/1444073
    • RS 现在是兼容性库的一部分,renderscript-v8.jar
    • 这里解释了对renderscript的支持:developer.android.com/tools/support-library/features.html
    • 这可行,但在 Galaxy S 3 上模糊半径 = 25 的 137KB 图像大约需要 2 秒。:(
    猜你喜欢
    • 2011-01-05
    • 2015-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多