Android高斯模糊
传送门
github地址:http://developer.android.com/guide/topics/renderscript/compute.html;
https://github.com/kikoso/android-stackblur。
csdn參考知识:http://blog.csdn.net/huli870715/article/details/39378349
感谢大神们的无私奉献,让我从小彩笔慢慢成长成大彩笔的梦想更近一步。
什么是高斯模糊(依据百科描写叙述)
高斯模糊能够把某一点周围的像素色值按高斯曲线统计起来,採用数学上加权平均的计算方法得到这条曲线的色值,最后能够留下人物的轮廓,即曲线。
全部的颜色只是都是数字,各种模糊只是都是算法。把要模糊的像素色值统计,用数学上加权平均的计算方法(高斯函数)得到色值。对范围、半径等进行模糊,大致就是高斯模糊。
高斯函数、正太分布、权重矩阵……有兴趣的人能够了解一下。我们主要还是调用【stackblur】开源项目中名为fastBlur的方法在java层直接进行高斯模糊处理。
依据网上的一些參考资料,以及自己项目实际的要求。一開始直接调用下述方法等到以及模糊后的效果图
private Bitmap blurImageAmeliorate(Bitmap sentBitmap,int radius, boolean canReuseInBitmap)
{
Bitmap bitmap;
if (canReuseInBitmap) {
bitmap = sentBitmap;
} else {
bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
}
if (radius < 1) {
return (null);
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int vmin[] = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int dv[] = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi++;
}
yw += w;
}
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi += w;
}
}
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return (bitmap);
}
结果没有问题,效果图就想网上描写叙述的一样。
但有一个问题就是直接使用原图进行高斯模糊处理的时间有点长。大概200毫秒左右,有明显的停顿感,即使用Handler异步处理,但图片展示的延后,用户体验明显下降。
stackOverflow对于程序猿来说永远是最大的宝藏。
http://stackoverflow.com/questions/2067955/fast-bitmap-blur-for-android-sdk这篇提问帖最终提供了新的解决思路:
This is a shot in the dark, but you might try shrinking the image and then enlarging it again. This can be done with Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter). Make sure and set the filter parameter to true. It’ll run in native code so it might be faster.
它所表述的原理为先通过缩小图片,使其丢失一些像素点,接着进行模糊化处理,然后再放大到原来尺寸。
因为图片缩小后再进行模糊处理,须要处理的像素点和半径都变小。从而使得模糊处理速度加快。
于是在高斯模糊算法之外我们套接一层,进行位图的缩小。
private void blur(Bitmap bkg, View view) {
float radius = 2;
float scaleFactor = 8;
Bitmap overlay = Bitmap.createBitmap((int)(view.getMeasuredWidth()/scaleFactor), (int)(view.getMeasuredHeight()/scaleFactor), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(overlay);
canvas.translate(-view.getLeft()/scaleFactor, -view.getTop()/scaleFactor);
canvas.scale(1 / scaleFactor, 1 / scaleFactor);
Paint paint = new Paint();
paint.setFlags(Paint.FILTER_BITMAP_FLAG);
canvas.drawBitmap(bkg, 0, 0, paint);
view.setBackground(new BitmapDrawable(getResources(), blurImageAmeliorate(overlay, (int)radius, true)));
}
Bitmap不懂,不经常使用有没有。。。
Canvas不懂,不经常使用有没有。。。
Paint不懂,不经常使用有没有。
。。
然后直接拿来调用最终的效果不错
那么问题来了,为什么背景图没有填充整个RelativeLayout呢。我们通过RelativeLayout.setBackground来设置背景。
各种測试后问题原因在于Canvas缩小的处理,对于Canvas实在不在行,知道问题所在,也解释不了。
如今回到正题。我们要做得是在高斯模糊处理之前得到一个缩小的位图,在此再感谢一下李刚老师的【疯狂Android讲义】。平时还是能够翻一翻,加深一些相关的知识。
通过调用Bitmap.createScaledBitmap方法,我们能够等到一个缩小后的位图。并且能顺利填充到组件背景,在效率上对照第一种快上不少,问题就如此处理了。。
。
除了Canvas的问题!
要用到高斯模糊上网查了非常久。其他的处理方式我这也从别人那copy一下,以备以后实用。(下面内容,我仅仅是用过一下下。出现的bug临时没有处理)
RenderScript
RenderScript是API11之后才引入的,所以对版本号有限制,并且RenderScript确实挺复杂的,尽管使用他的Blur功能非常easy,可是要真正搞懂,不是一天两天的事。学习文档:http://developer.android.com/guide/topics/renderscript/compute.html
private void blur(Bitmap bkg, View view) {
long startMs = System.currentTimeMillis();
float radius = 20;
Bitmap overlay = Bitmap.createBitmap((int)(view.getMeasuredWidth()), (int)(view.getMeasuredHeight()), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(overlay);
canvas.translate(-view.getLeft(), -view.getTop());
canvas.drawBitmap(bkg, 0, 0, null);
RenderScript rs = RenderScript.create(SecondActivity.this);
Allocation overlayAlloc = Allocation.createFromBitmap(rs, overlay);
ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(rs, overlayAlloc.getElement());
blur.setInput(overlayAlloc);
blur.setRadius(radius);
blur.forEach(overlayAlloc);
overlayAlloc.copyTo(overlay);
view.setBackground(new BitmapDrawable(getResources(), overlay));
rs.destroy();
statusText.setText("cost " + (System.currentTimeMillis() - startMs) + "ms");
}
布局代码就不具体的copy过来了。实现这种方法一个要求最低的sdk版本号是11,对于硬件要求是17。也就是说假设手机Android版本号是4.2下面的话。应该是用不了的。我測试机还是小米1,让我呵呵一笑。
以上差点儿相同是自己这次接触高斯模糊所见所学,有不足之处,请大家谅解。
Android高斯模糊的更多相关文章
- android 高斯模糊实现
高斯模糊 高斯模糊就是将指定像素变换为其与周边像素加权平均后的值,权重就是高斯分布函数计算出来的值. 一种实现 点击打开链接<-这里是一片关于高斯模糊算法的介绍,我们需要首先根据高斯分布函数计算 ...
- Android高斯模糊实现方案
1.使用Glide Glide.with(this) .load(service.getImageUri()) .dontAnimate() .error(R.drawable.error_img) ...
- Android高斯模糊技术,实现毛玻璃效果(转)
本博客转自郭霖公众号:http://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650235930&idx=1&sn=e328 ...
- Android开发学习之路-动态高斯模糊怎么做
什么是高斯模糊? 高斯模糊(英语:Gaussian Blur),也叫高斯平滑,是在Adobe Photoshop.GIMP以及Paint.NET等图像处理软件中广泛使用的处理效果,通常用它来减少图像噪 ...
- Android 图片滤镜工具——高斯模糊
===================高斯模糊========================= 创建一个 ImageFilter 类(滤镜工具),代码如下: import android.graph ...
- Android图像处理 - 高斯模糊的原理及实现
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 由 天天P图攻城狮 发布在云+社区 作者简介:damonxia(夏正冬),天天P图Android工程师 前言 高斯模糊是图像处理中几乎每个程序员 ...
- Android 图片高级绘图效果---高斯模糊
高斯模糊就是将指定像素变换为其与周边像素加权平均后的值,权重就是高斯分布函数计算出来的值.高斯模糊能够将图片制作成类似磨砂的图片效果,一般这些图片都用来作为背景. 目前使用到的是RenderScrip ...
- 封装个 Android 的高斯模糊组件
本篇文章已授权微信公众号 hongyangAndroid (鸿洋)独家发布 最近基于 Android StackBlur 开源库,根据自己碰到的需求场景,封装了个高斯模糊组件,顺便记录一下. 为什么要 ...
- [Android]-图片JNI(C++\Java)高斯模糊的实现与比較
版权声明:本文作者:Qiujuer https://github.com/qiujuer; 转载请注明出处,盗版必究! !! https://blog.csdn.net/qiujuer/article ...
随机推荐
- SSH框架的简化
---恢复内容开始--- 一.简易化的SSH框架,如图: SSH框架的搭建,我就不多说了. 二.简易的ssh框架的步骤: 1.重新编写applicationContext.xmlwen文件 <一 ...
- ring3 dll hide
ZwQuerySystemInformation(SystemProcessInformation,SystemInformation,Length,ReturnLength); pS ...
- BZOJ 3566: [SHOI2014]概率充电器( 树形dp )
通过一次dfs求出dp(x)表示节点x考虑了x和x的子树都没成功充电的概率, dp(x) = (1-p[x])π(1 - (1-dp[son])*P(edge(x, son)).然后再dfs一次考虑节 ...
- Html页面加回滚
<div class="top-box"> <img src=" class="youlink-img" /><br / ...
- 搭建Hadoop集群 (三)
通过 搭建Hadoop集群 (二), 我们已经可以顺利运行自带的wordcount程序. 下面学习如何创建自己的Java应用, 放到Hadoop集群上运行, 并且可以通过debug来调试. 有多少种D ...
- for循环产生的Cortex-M3汇编代码的一个奇怪现象
最近比较一下KEIL和IAR两个编译器产生的代码,基于Cortex-M3处理器的,然后发现了一几个奇怪的地方. 很简单的一个C的for循环 void fun_for_add_65535(void) { ...
- 大数据技术 vs 数据库一体机[转]
http://blog.sina.com.cn/s/blog_7ca5799101013dtb.html 目前,虽然大数据与数据库一体机都很火热,但相当一部分人却无法对深入了解这两者的本质区别.这里便 ...
- C++可变参数的另一种实现
大家熟知的C库函数printf函数就是一个可变参数函数,它是怎么实现的呢?不过他实现是有条件的,必须函数参数的入栈顺序为从右向左的顺序,也即函数的形参,在函数调用之前,必须是最右边的参数先入栈,并且参 ...
- QT小记之在VS2005中使用(设置QMAKESPEC环境变量,以及编译QT Lib)
QT的结构很清晰明了,看过第一个HELLO WORLD便爱上了它,感觉CEGUI有借鉴过QT的设计.如何在Windows平台下使用QT开发?一,下载SDK包请去官网(QT被NOKIA收购,貌似使用协议 ...
- cocos2d-x过程动作CCProgressTo示例学习笔记
// // SpriteProgressToRadial // //------------------------------------------------------------------ ...