加载和使用缩小的位图(对于非常模糊的图像)

永远不要使用完整大小的位图。图像越大,需要模糊的越多,模糊半径也需要越高,通常,模糊半径越高,算法所需的时间就越长。

缩小位图的两种方式

1.位图options缩小

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap blurTemplate = BitmapFactory.decodeResource(getResources(), bitmap, options);

加载8 位图,因此只有原始图像的 1/64。inSampleSize可以根据需要修改,但需要满足条件 2^n (2,4,8,...) ,以避免因缩放而降低质量。

2.位图Scale缩小

Bitmap bitmap = ...;
float BITMAP_SCALE = 0.4f;
int width = Math.round(bitmap .getWidth() * BITMAP_SCALE);
int height = Math.round(bitmap .getHeight() * BITMAP_SCALE);
// 将缩小后的图片做为预渲染的图片
Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap , width, height, false);

使用渲染脚本模糊

Renderscript 提供
了一个高斯模糊滤镜ScriptIntrinsicBlur。它具有良好的视觉质量,使得位图在 Android上获得的更快速度。Google 声称“通常比多线程 C 实现快 2-3 倍,通常比 Java 实现快 10 倍以上”
。Renderscript 非常复杂(使用最快的处理设备(GPU、ISP 等)等),在理论上,通过测试和其他开发人员的报告,不可盲目地使用 Renderscript,因为硬件/驱动程序碎片似乎会导致某些设备出现问题。

// 图片缩放比例(即模糊度)
private static final float BITMAP_SCALE = 0.4f;
/*** @param context 上下文对象* @param srcBitmap   需要模糊的图片* @return 模糊处理后的Bitmap*/
public static Bitmap blurBitmap(Context context, Bitmap srcBitmap, float blurRadius) {// 计算图片缩小后的长宽int width = Math.round(srcBitmap.getWidth() * BITMAP_SCALE);int height = Math.round(srcBitmap.getHeight() * BITMAP_SCALE);// 将缩小后的图片做为预渲染的图片Bitmap inputBitmap = Bitmap.createScaledBitmap(srcBitmap, width, height, false);// 创建一张渲染后的输出图片Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);// 创建RenderScript内核对象RenderScript rs = RenderScript.create(context);// 创建一个模糊效果的RenderScript的工具对象ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));// 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间// 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);// 设置渲染的模糊程度, 25f是最大模糊度blurScript.setRadius(blurRadius);// 设置blurScript对象的输入内存blurScript.setInput(tmpIn);// 将输出数据保存到输出内存中blurScript.forEach(tmpOut);// 将数据填充到Allocation中tmpOut.copyTo(outputBitmap);rs.destroy();return outputBitmap;
}
android {...defaultConfig {...renderscriptTargetApi 19renderscriptSupportModeEnabled true}
}

尽可能重用位图(如果优先:性能 > 内存占用)

如果需要多个模糊来进行实时模糊或类似操作,并且内存允许它不会多次从可绘制对象中加载位图,而是将其“缓存”在成员变量中。在这种情况下,请始终尝试使用相同的变量,以将垃圾收集降至最低。

使用RGB点模糊

java代码(比脚本模糊慢,但是开原程度高)

public static Bitmap fastBlur(Bitmap sentBitmap, float scale, int radius) {int width = Math.round(sentBitmap.getWidth() * scale);int height = Math.round(sentBitmap.getHeight() * scale);sentBitmap = Bitmap.createScaledBitmap(sentBitmap, width, height, false);Bitmap 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++) {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;
}

JNI代码(性能没有测试)

#include <jni.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <android/log.h>
#include <android/bitmap.h>#define LOG_TAG "libbitmaputils"
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)typedef struct {uint8_t red;uint8_t green;uint8_t blue;uint8_t alpha;
} rgba;JNIEXPORT void JNICALL Java_com_insert_your_package_ClassName_functionToBlur(JNIEnv* env, jobject obj, jobject bitmapIn, jobject bitmapOut, jint radius) {LOGI("Blurring bitmap...");// PropertiesAndroidBitmapInfo   infoIn;void*               pixelsIn;AndroidBitmapInfo   infoOut;void*               pixelsOut;int ret;// Get image infoif ((ret = AndroidBitmap_getInfo(env, bitmapIn, &infoIn)) < 0 || (ret = AndroidBitmap_getInfo(env, bitmapOut, &infoOut)) < 0) {LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);return;}// Check imageif (infoIn.format != ANDROID_BITMAP_FORMAT_RGBA_8888 || infoOut.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {LOGE("Bitmap format is not RGBA_8888!");LOGE("==> %d %d", infoIn.format, infoOut.format);return;}// Lock all imagesif ((ret = AndroidBitmap_lockPixels(env, bitmapIn, &pixelsIn)) < 0 || (ret = AndroidBitmap_lockPixels(env, bitmapOut, &pixelsOut)) < 0) {LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);}int h = infoIn.height;int w = infoIn.width;LOGI("Image size is: %i %i", w, h);rgba* input = (rgba*) pixelsIn;rgba* output = (rgba*) pixelsOut;int wm = w - 1;int hm = h - 1;int wh = w * h;int whMax = max(w, h);int div = radius + radius + 1;int r[wh];int g[wh];int b[wh];int rsum, gsum, bsum, x, y, i, yp, yi, yw;rgba p;int vmin[whMax];int divsum = (div + 1) >> 1;divsum *= divsum;int dv[256 * divsum];for (i = 0; i < 256 * divsum; i++) {dv[i] = (i / divsum);}yw = yi = 0;int stack[div][3];int stackpointer;int stackstart;int rbs;int ir;int ip;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 = input[yi + min(wm, max(i, 0))];ir = i + radius; // same as sirstack[ir][0] = p.red;stack[ir][1] = p.green;stack[ir][2] = p.blue;rbs = r1 - abs(i);rsum += stack[ir][0] * rbs;gsum += stack[ir][1] * rbs;bsum += stack[ir][2] * rbs;if (i > 0) {rinsum += stack[ir][0];ginsum += stack[ir][1];binsum += stack[ir][2];} else {routsum += stack[ir][0];goutsum += stack[ir][1];boutsum += stack[ir][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;ir = stackstart % div; // same as sirroutsum -= stack[ir][0];goutsum -= stack[ir][1];boutsum -= stack[ir][2];if (y == 0) {vmin[x] = min(x + radius + 1, wm);}p = input[yw + vmin[x]];stack[ir][0] = p.red;stack[ir][1] = p.green;stack[ir][2] = p.blue;rinsum += stack[ir][0];ginsum += stack[ir][1];binsum += stack[ir][2];rsum += rinsum;gsum += ginsum;bsum += binsum;stackpointer = (stackpointer + 1) % div;ir = (stackpointer) % div; // same as sirroutsum += stack[ir][0];goutsum += stack[ir][1];boutsum += stack[ir][2];rinsum -= stack[ir][0];ginsum -= stack[ir][1];binsum -= stack[ir][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 = max(0, yp) + x;ir = i + radius; // same as sirstack[ir][0] = r[yi];stack[ir][1] = g[yi];stack[ir][2] = b[yi];rbs = r1 - abs(i);rsum += r[yi] * rbs;gsum += g[yi] * rbs;bsum += b[yi] * rbs;if (i > 0) {rinsum += stack[ir][0];ginsum += stack[ir][1];binsum += stack[ir][2];} else {routsum += stack[ir][0];goutsum += stack[ir][1];boutsum += stack[ir][2];}if (i < hm) {yp += w;}}yi = x;stackpointer = radius;for (y = 0; y < h; y++) {output[yi].red = dv[rsum];output[yi].green = dv[gsum];output[yi].blue = dv[bsum];rsum -= routsum;gsum -= goutsum;bsum -= boutsum;stackstart = stackpointer - radius + div;ir = stackstart % div; // same as sirroutsum -= stack[ir][0];goutsum -= stack[ir][1];boutsum -= stack[ir][2];if (x == 0) vmin[y] = min(y + r1, hm) * w;ip = x + vmin[y];stack[ir][0] = r[ip];stack[ir][1] = g[ip];stack[ir][2] = b[ip];rinsum += stack[ir][0];ginsum += stack[ir][1];binsum += stack[ir][2];rsum += rinsum;gsum += ginsum;bsum += binsum;stackpointer = (stackpointer + 1) % div;ir = stackpointer; // same as sirroutsum += stack[ir][0];goutsum += stack[ir][1];boutsum += stack[ir][2];rinsum -= stack[ir][0];ginsum -= stack[ir][1];binsum -= stack[ir][2];yi += w;}}// Unlocks everythingAndroidBitmap_unlockPixels(env, bitmapIn);AndroidBitmap_unlockPixels(env, bitmapOut);LOGI ("Bitmap blurred.");
}int min(int a, int b) {return a > b ? b : a;
}int max(int a, int b) {return a > b ? a : b;
}

Android Bitmap高斯模糊相关推荐

  1. android 开源 高斯模糊_Android高斯模糊、高斯平滑(Gaussian Blur)【1】

     Android高斯模糊.高斯平滑(Gaussian Blur)[1] Android高斯模糊.高斯平滑(Gaussian Blur),图形图像处理的一种效果,经过高斯模糊处理后的图片有一种&qu ...

  2. Android使用高斯模糊实现模糊背景

    Android使用高斯模糊实现模糊背景 引言 最近的开发中实现了一个模糊背景的效果.大概效果是这样的: 实现思路 将View转成Bitmap,并且记录列表的滑动距离,生成bitmap时上移画布(这样是 ...

  3. Android 图片高斯模糊解决方案

    Android 图片高斯模糊解决方案 近年来,图片高斯模糊备受设计师的青睐,在各大知名APP中,如微信.手机QQ.网易云音乐等等都有对背景高斯图模糊的设计,在Adnroid 中,现在常用的图片高斯模糊 ...

  4. Android Bitmap转换WebP图片导致损坏的分析及解决方案

    Android Bitmap转换WebP图片导致损坏的分析及解决方案 参考文章: (1)Android Bitmap转换WebP图片导致损坏的分析及解决方案 (2)https://www.cnblog ...

  5. Android bitmap图片处理

    一.View转换为Bitmap         在Android中所有的控件都是View的直接子类或者间接子类,通过它们可以组成丰富的UI界面.在窗口显示的时候Android会把这些控件都加载到内存中 ...

  6. Android Bitmap 研究与思考(上篇)

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/107951273 本文出自[赵彦军的博客] 做Android 6年来,一直都没有对 ...

  7. Android—Bitmap图片大小计算、压缩与三级缓存

    Bitmap对象占用内存大小: bitmap.getByteCount() 图片所占内存大小计算方式:图片长度 x 图片宽度 x 一个像素点占用的字节数. Android Bitmap使用的三种颜色格 ...

  8. android bitmap string,Android Bitmap到Base64字符串(Android Bitmap to Base64 String)

    Android Bitmap到Base64字符串(Android Bitmap to Base64 String) 如何将一个大的Bitmap(用手机相机拍摄的照片)转换为Base64 String? ...

  9. Android Bitmap OutOfMemory 解决办法

    Android Bitmap OutOfMemory 解决办法 置顶 2014年07月01日 14:41:22 阅读数:3072 标签: OutOfMemoryBitmapandroid图片优化更多 ...

最新文章

  1. ps -ef |grep 输出的具体含义
  2. python的应用领域有哪些、选择题_Python程序的设计复习题与答案
  3. hdu 1863(最小生成树kruskal)
  4. linux red hat 安装svn
  5. layui 在springboot2.x 时,页面展示不了layui的问题
  6. android tmp目录权限不够,/tmp目录下执行脚本失败提示Permission denied
  7. AgileEAS.NET SOA 中间件Web运行容器管理功能已全部开源,欢迎大家下载、使用、反馈...
  8. oracle 体系结构初步认识(一)
  9. ##R语言生信作图之UpsetR做交集图
  10. docker 基本指令
  11. Flutter 自定义CheckBox (用于兴趣爱好、风格选择)
  12. 阴历日期和阳历日期互相转换(java)
  13. 跨境电商ERP系统基础开发教程
  14. 虚拟机NAT模式的网络设置
  15. Diagrams(draw.io)-怎样实现跨线
  16. Java后端技术框架
  17. 用Selenium+xpath爬取京东商城
  18. 全球公认的最健康作息时间表(2015就照个来)
  19. layui 表无法渲染问题
  20. AHK 实现中英文输入法自由

热门文章

  1. java mongodb集群配置,MongoDB集群JavaAPI插入数据
  2. 另劈捷径实现微信小程序与公众号的OpenID建立关联
  3. 圈粉无数的B站美妆UP主@机智的党妹,她的涨粉秘诀是什么?
  4. Java中的WADL:温和的介绍
  5. Delphi TColor和16进制颜色 html的相互转换
  6. 一文看懂特权访问管理(PAM)
  7. 【Java进阶】02-线程(中)
  8. matlab 图中的legend,matlab中legend加图示命令的使用
  9. Linux小技巧之密码更改
  10. React滚动页面触发相应位置动画