设为首页 加入收藏

TOP

封装个 Android 的高斯模糊组件(一)
2019-09-01 23:14:26 】 浏览:54
Tags:封装 Android 高斯 模糊 组件

本篇文章已授权微信公众号 hongyangAndroid (鸿洋)独家发布

最近基于 Android StackBlur 开源库,根据自己碰到的需求场景,封装了个高斯模糊组件,顺便记录一下。

为什么要自己重复造轮子?

其实也谈不上重头自己造轮子,毕竟是基于大神的开源库,做了二次封装。封装的目的在于,方便外部使用。毕竟有着自己的编程习惯,大神的开源库也只是提供了基础的功能,现实编程中,产品的需求是各种各样的。

导致每次使用时,都蛮麻烦的,需要额外自己处理蛮多东西。而一旦新的项目又需要接入高斯模糊了,又得重新写一些代码,复制粘贴也麻烦,经常由于各种业务耦合报错。

既然如此,干脆花时间抽个基础、公用的高斯模糊组件,需要时直接依赖即可。

基础理论

高斯模糊

高斯模糊的原理和算法就不介绍了,我也不懂,没深入,这里就大概讲讲我的粗坯理解:

我们知道,一张图片,本质上其实是一个个像素点构成的,虽然经过计算机处理后,呈现在我们眼前的是具体的图像。但在计算机中,其实就是一堆数组数据。

数组中每个单位就是一个个像素点,那么每个像素点是存储什么内容呢,其实也就是 RGB 或者 ARGB 之类格式的数据。

高斯模糊,大体上就是对这张图片中的每个像素点都重新进行计算,每个像素点的新值等于以它为中心,半径为 r 的周围区域内所有像素点各自按照不同权重相加之和的平均值。

可以粗坯的理解为,本来这个像素点是要呈现它自己本身的内容,但经过高斯模糊计算后,掺杂进它周围区域像素点的内容了。就像加水稀释类似的道理,既然都掺杂进周围的内容了,那么它呈现的内容相比最初,肯定就不那么清晰了

而如果掺杂的半径越大,混合进的内容也就越多,那么它本身的内容就越淡了,是不是这个理。所以,这就是为什么每个开源的高斯模糊组件库,使用时基本都需要我们传入一个 radius 半径的参数。而且,半径越大,越模糊。

这么一粗坯的解释,就理解多了,是吧。

为什么需要大概掌握这个理论基础呢?

想想,高斯模糊是遍历所有像素点,对每个像素点都重新计算。那么,这自然是一个耗时的工作,掌握了理论基础,我们要优化时也才有方向去优化。

性能对比

大神的开源库中提供了三种高斯模糊方式,而我在 Blankj 的 AndroidUtilCode 开源库中发现了另外一种,所以我将他们都整合起来,一共有四种:

  • Google 官方提供的 RenderScript 方式 (RSBlur)
  • C 编写的高斯算法 blur.c 方式 (NativeBlur)
  • Java 编写的高斯算法方式1(JavaBlur)
  • Java 编写的高斯算法方式2(StackBlur)

其实,大体上就三种:Google 官方提供的,大神用 C 写的高斯模糊算法,大神用 Java 写的高斯模糊算法。至于后面两种,看了下,算法的代码不一样,我就把它们当做是两种不同的算法实现了。也许是一样,但我没深入去看,反正代码不一样,我就这么认为了。

下面我们来做个实验,在如下相同条件下,不同高斯模糊方案的耗时比较:

  • radius=10, scale=1, bitmap=200*200(11.69KB)

ps: radius 表示高斯算法计算过程中的半径取值,scale=1表示对 bitmap 原图进行高斯模糊。这些前提条件需要了解一下,不然你在看网上其他类似性能比对的文章时,发现它们动不动就优化到几 ms 级别的,然而你自己尝试却始终达不到。这是因为也许所使用的这些前提都不一致,不一致的前提下,耗时根本无从比较。

private void testBlur() {
    int sum = 0;
    for (int i = 0; i < 100; i++) {
        long time = SystemClock.uptimeMillis();
        DBlur.source(this, R.drawable.image).modeRs().radius(10).sampling(1).build().doBlurSync();
        long end = SystemClock.uptimeMillis();
        sum += (end - time);
    }
    Log.e("DBlur", "RSBlur cast " + (sum/100) + "ms");
}

代码模板如上,分别运行 100 次后取平均值,四种不同方式的耗时如下表:

前提条件 RSBlur NativeBlur JavaBlur StackBlur
radius=10, scale=1, bitmap=200*200 51ms 13ms 162ms 384ms
radius=20, scale=1, bitmap=200*200 56ms 12ms 164ms 435ms
radius=10, scale=2, bitmap=200*200 48ms 11ms 75ms 110ms
radius=10, scale=8, bitmap=200*200 45ms 7ms 14ms 19ms
radius=10, scale=8, bitmap=1920*1180 183ms 143ms 346ms 460ms
radius=20, scale=8, bitmap=1920*1180 204ms 145ms 353ms 510ms
radius=20, scale=1, bitmap=1920*1180 474ms 444ms 8663ms 内存溢出

100 次样本可能不多,但大体上我们也能比较出不同类型的高斯模糊之前的区别,及其适用场景:

  • 总体上,NativeBlur 和 RSBlur 的耗时会少于 JavaBlur 和 StackBlur
  • JavaBlur 和 StackBlur 方式,如果先对 Bitmap 进行缩小,再高斯模糊,最后再放大,耗时会大大缩短
  • radius 增大会增加耗时,但影响不大,但视图呈现效果会越模糊
  • scale 对原图缩小倍数越多,耗时越短,但视图呈现效果同样会越模糊
  • 分辨率越高的图片,高斯模糊的就越耗时
  • 对于大图而言,如果要使用 JavaBlur 或 StackBlur,最好设置 scale 先缩小再模糊,否则将非常耗时且容易内存溢出
  • 如果已经通过 scale 方式进行优化,那么最好 radius 值可以相对小一点,否则两者的值都大会对图片的模糊效果特别强烈,也许会过了头

性能优化

高斯模糊的优化考虑点,其实就三个:

  • 选择不同的高斯模糊方式
  • 通过 scale 对原图先缩小,再模糊,最后再放大方式
  • 优化高斯模糊算法

最后一点就不考虑了,毕竟难度太大。那么,其实就剩下两种,要么是从高斯模糊的方案上选择,要么从待模糊的图片上做手脚。

虽然有四种高斯模糊方案,但每种都有各自优缺点:

  • RSBlur 在低端机上可能无法兼容
  • NativeBlur 需要生成对应 CPU 架构的 so 文件支持
  • JavaBlur 和 StackBlur 耗时会较长

优化的考虑点大体上这几种:

  • 大体上,使用 NativeBlur 或者 RSBlur 即可,如果出现一些问题,那么此时可考虑切到 JavaBlur 或 StackBlur 方案,但记得结合 scale 方式优化处理。
  • 如果高斯模糊的图片有实时性要求,要求模糊得同步进行处理,主线程后续的工作需要等待高斯模糊后才能够处理的话,那么尽量选择 scale 方式进行优化,
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇VR一体机如何退出FFBM(QFIL) 下一篇高通平台如何避免误入FFBM模式

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目