Android图像处理 - 高斯模糊的原理及实现
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~
由 天天P图攻城狮 发布在云+社区
作者简介:damonxia(夏正冬),天天P图Android工程师
前言
高斯模糊是图像处理中几乎每个程序员都或多或少听过的名词,但是对其原理大家可能并不了解,只知道通过高斯模糊能实现图像毛玻璃效果。
本文首先介绍图像处理中最基本的概念:卷积;随后介绍高斯模糊的核心内容:高斯滤波器;接着,我们从头实现了一个Java版本的高斯模糊算法,以及实现RenderScript版本。由于我们自己实现的Java版本的高斯模糊算法的效率太低,因此最后介绍比较有名的高斯模糊的开源项目:Blurry以及BlurKit-Android。
BlurDemo是本文的配套Demo:
- Demo1:Java版本的高斯模糊的简单实现。
- Demo2:RenderScript的高斯模糊实现。
- Demo3:BlurKit-Android的基本使用。
- Demo4:Blurry的基本使用。
卷积
本文只讨论图像,而图像可以表示为二维矩阵,其中每个元素为ARGB像素值,因此这里讨论二维矩阵的卷积操作。卷积(Convolution)是图像处理中最基本的操作,就是一个二维矩阵A(M*N)和一个二维矩阵B(m*n)做若干操作,生成一个新的二维矩阵C(M*N),其中m和n远小于M和N,B称为卷积核(kernel),又称滤波器矩阵或模板。
这里举个卷积的例子,如图:

上图中,最左边的是源矩阵(8*8),中间是卷积核(3*3,半径为1),最右边是通过对前面两个矩阵做卷积生成的结果矩阵。图中,如果我们要求出结果矩阵中第二行第二列的元素的值,则把卷积核的中心元素(值为0)和源矩阵的第二行第二列(值为6)对齐,然后求加权和,即图中的公式,最后得到-3。
我们再举一个例子:

上图也展示了如何做卷积的过程,比如要求出结果矩阵中第一行第一列的值,则把卷积核的中心对准源矩阵的第一行第一列,发现部分区域超出源矩阵的范围了(图中红色部分),解决方法有很多,这里的方案是:用边界值填充。接着做加权和,结果为-5。接着用同样的方法依次计算结果矩阵的每个元素即可。
通常来说卷积核需要满足:
- 宽和高都为奇数,这样才会有半径和中心的概念。
- 元素总和为1。
滤波器
均值滤波器
均值滤波器(Mean Filter)是最简单的一种滤波器,它是最粗糙的一种模糊图像的方法,高斯滤波是均值滤波的高级版本。实际上不同的滤波器就是通过改变卷积核(滤波器),从而改变最后的结果矩阵,中间步骤都一样,都是求加权和。均值滤波器的卷积核通常是m*m的矩阵,其中每个元素为1/(m^2),可以看出卷积核的元素总和为1。比如3*3的均值滤波器,卷积核的每个元素就是1/9。
高斯滤波器
高斯滤波器是均值滤波器的高级版本,唯一的区别在于,均值滤波器的卷积核的每个元素都相同,而高斯滤波器的卷积核的元素服从高斯分布。
高斯滤波器是基于二维的高斯分布函数,因此首先介绍二维高斯分布函数。二维高斯分布函数和图如下:

其中x和y表示卷积核中某个元素横坐标和纵坐标距离中心点的距离。sigma控制曲线的平缓程度,值越大,越平缓,最高点越低。我们可以轻易看出当x=0且y=0时值最大,即卷积核的中心点权重最大。
比如卷积核中一个元素距离中心点,横向距离2,纵向距离1,那么x=2,y=1,就能求出该元素的值。当然为了保证卷积核元素总和为1,最后每个元素都需要除以卷积核中所有元素之和。
怎么确定卷积核的大小呢?确定sigma之后,虽然不管距离中心点多远,该元素的高斯分布函数值总为非负数,但是根据经验,卷积核的半径定为3*sigma,因此宽高为6*sigma+1。
如果高斯滤波器的卷积核是二维的(m*n),则算法复杂度为O(m*n*M*N),复杂度较高,因此接下来我们对算法复杂度进行优化。
一维的高斯分布函数和图如下:

实际上,二维高斯分布函数可以分解为两个一维高斯分布函数相乘,如下:

因此原本的源矩阵和二维卷积核做卷积等价于源矩阵先与1*m的一维卷积核做卷积,再与m*1的一维卷积核做卷积。一维卷积核的半径仍定为3*sigma。此时算法复杂度变为O(2*m*M*N)。
高斯模糊的实现
Java版本
这里实现了简单版本的高斯模糊,通过使用横向和纵向的一维高斯滤波器分别对源矩阵卷积,通过设置sigma的大小能控制图片的模糊程度,值越大越模糊。但是算法速度仍比较慢,建议直接使用RenderScript版本或直接使用成熟的开源项目。
由于代码过长,不能截图,因此直接给出Gist地址:https://gist.github.com/xiazdong/d57bf5441f56db197163a5de69dfa65f
效果如下:

RenderScript版本
RenderScript是Android提出的一个计算密集型任务的高性能框架,能并行的处理任务,他可以充分利用多核CPU和GPU,你不需要管怎么调度你的任务,只需要管任务具体做什么。这里不深入介绍RenderScript,因为RenderScript已经提供了一个实现高斯模糊的类:ScriptIntrinsicBlur。
实现起来非常简单:

开源项目
关于Android图像模糊的开源项目有很多,比如Blurry是专门针对Bitmap或View做模糊,可以设置模糊的基底色,而且还能对模糊操作异步化;BlurKit-Android也能对Bitmap做高斯模糊(内部通过RenderScript实现),但最吸引人的是实现了毛玻璃的遮罩,效果如下:

BlurKit-Android支持的最低版本是Android 4.1(API 16),因此如果应用需要支持的最低版本是4.0,则不能使用该库,Blurry支持的最低版本是3.0。
BlurKit-Android
配置过程如下:
- 在build.gradle中设置:
compile 'com.wonderkiln:blurkit:1.0.0',并在defaultConfig中设置renderscriptTargetApi 24和renderscriptSupportModeEnabled true。 - 在Application的onCreate()最开始处加入
BlurKit.init(this);。
配置完成后,通过调用BlurKit.getInstance().blur(Bitmap src, int radius);实现高斯模糊,并会把高斯模糊的结果图写入src,其中0<radius<=25。
该库还提供了fastBlur()实现速度更快的高斯模糊,和blur()的区别在于,fastBlur()在高斯模糊之前对图片采样,使得图片大小缩小好几倍,从而加快高斯模糊的速度。这种加快速度的方法是合理的,因为高斯模糊并不需要原图像很精确的信息。
BlurKit-Android最吸引人的是提供高斯模糊的遮罩(BlurLayout),随着遮罩下面的内容的变化,高斯模糊效果也会随之改变。使用如下:

该Layout能够实现实时的对该Layout下面的内容做高斯模糊。
Blurry
配置方法:在build.gradle中添加compile 'jp.wasabeef:blurry:2.1.1'。
使用方法如下:

总的来说,这两个库都使用起来非常方便。
相关阅读
此文已由作者授权云加社区发布,转载请注明文章出处
Android图像处理 - 高斯模糊的原理及实现的更多相关文章
- Atitit Gaussian Blur 高斯模糊 的原理and实现and 用途
Atitit Gaussian Blur 高斯模糊 的原理and实现and 用途 1.1. 高斯模糊 的原理(周边像素的平均值+正态分布的权重1 1.2. 高斯模糊 的用途(磨皮,毛玻璃效果,背景虚化 ...
- 封装个 Android 的高斯模糊组件
本篇文章已授权微信公众号 hongyangAndroid (鸿洋)独家发布 最近基于 Android StackBlur 开源库,根据自己碰到的需求场景,封装了个高斯模糊组件,顺便记录一下. 为什么要 ...
- android图像处理系列之七--图片涂鸦,水印-图片叠加
图片涂鸦和水印其实是一个功能,实现的方式是一样的,就是一张大图片和一张小点图片叠加即可.前面在android图像处理系列之六--给图片添加边框(下)-图片叠加中也讲到了图片叠加,里面实现的原理是直接操 ...
- android 图像处理系列合集
为了便于大家对滤镜算法的学习,以后发布的图像处理滤镜系列帖子会在这里汇总,本人第一次写合集,写得不好的地方大家请见谅,手头上虽然有一些滤镜的算法,但是大多不是android版的,教程里的代码大多是我借 ...
- (转)Android 系统 root 破解原理分析
现在Android系统的root破解基本上成为大家的必备技能!网上也有很多中一键破解的软件,使root破解越来越容易.但是你思考过root破解的 原理吗?root破解的本质是什么呢?难道是利用了Lin ...
- Android图像处理实例教程
Android图像处理实例教程 原始出处 http://vaero.blog.51cto.com/4350852/856750
- Android系统Recovery工作原理
Android系统Recovery工作原理之使用update.zip升级过程分析(一)---update.zip包的制作 http://blog.csdn.net/mu0206mu/article/d ...
- Android图像处理1
项目开发要用,在慕课中学习了一下关于Android图像处理的相关功能,并进行了整理. 在Android中,我们通过最基本的改变图像的RGBA值,改变图像的颜色与饱和度. Android中有ColorM ...
- Android启动篇 — init原理(二)
======================================================== ================================== ...
随机推荐
- [51nod1676]无向图同构
如果一个无向图重标号后与另一个无向图完全一致(即对于任意两点,他们之间的边在两个图中都存在或都不存在),则称两个无向图同构. 给定两个n个点m条边的无向图,判定两个无向图是否同构.不超过20组数据,n ...
- c语言几个松散的地方(不足的地方,不严谨的地方,它容易出错的地方)。
c语言是面向过程的语言,是弱类型语言,c语言的源代码基本就是无数个函数的堆砌.即很多函数就组成c语言源代码了,也即它的源代码基本就是函数构成的. C语言里面的test()和test(void)是不一样 ...
- 对于hive使用的一点记录
最近一段时间因工作需要接触了一些hive上的使用!当然大部分都是比较基本的使用,仅当入门!各位看到有不足之处望多多指正! 废话不多说,开始: 首先是创建数据库 create database '数据库 ...
- git工作流程一览
Git是分布式版本控制系统,没有中央服务器,每个人的电脑就是一个完整的版本库,工作的时候不需要联网了,因为版本都在自己电脑上.协同的方法是这样的:比如说自己在电脑上改了文件A,其他人也在电脑上改了文件 ...
- 支付宝当面付开发(java)
支付宝当面付开发(java) 业务流程: 接入准备: 直接下载demo: https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7 ...
- 图解vue生命周期
学习vue时搞清楚生命周期可以帮助你知道什么时候在什么地方执行该执行的方法,话不多说上图: 复制下面代码可以在控制台更详细展示各个钩子的状态 <!DOCTYPE html> <htm ...
- 读懂_countof,可以懂得什么
在c++开发中数组是我们经常使用存储结构,而于此同时"数组越界"是每个c++程序员不能不提防陷阱. 还好,我们有预定义宏_countof. 一.在visual c++开发环境下,它 ...
- phpstorm ctrl+shift+F键不管用,不弹出搜索弹框
般热键冲突搜狗默认简繁切换组合键位ctrl+shift+F故outlook2011按三建且失效应该能看搜狗输入状态简繁变搜狗设置按键-取消选简繁切换热键即在任务栏的语言地方点击一下再点击语言首选项.进 ...
- ecshop_添加最新评论
第一步: 在includes/lib_goods.php里面构建自定义函数 代码如下: /** * 获取最近评论 * * @return array */ function get_latest ...
- 【笔记】vue-cli 开发环境中跨域连接后台api(vue-resource 跨域post 请求)
在vue-cli 项目中很多人会用到mock 数据(模拟数据),但是我觉得如果在真实的数据库交互中开发会更有安全感一些,所以查了一下百度很多人推荐的就是: 跨域! 跨域是什么概念?不同的主机名,同主机 ...