Android Bitmap高斯模糊
加载和使用缩小的位图(对于非常模糊的图像)
永远不要使用完整大小的位图。图像越大,需要模糊的越多,模糊半径也需要越高,通常,模糊半径越高,算法所需的时间就越长。
缩小位图的两种方式
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高斯模糊相关推荐
- android 开源 高斯模糊_Android高斯模糊、高斯平滑(Gaussian Blur)【1】
Android高斯模糊.高斯平滑(Gaussian Blur)[1] Android高斯模糊.高斯平滑(Gaussian Blur),图形图像处理的一种效果,经过高斯模糊处理后的图片有一种&qu ...
- Android使用高斯模糊实现模糊背景
Android使用高斯模糊实现模糊背景 引言 最近的开发中实现了一个模糊背景的效果.大概效果是这样的: 实现思路 将View转成Bitmap,并且记录列表的滑动距离,生成bitmap时上移画布(这样是 ...
- Android 图片高斯模糊解决方案
Android 图片高斯模糊解决方案 近年来,图片高斯模糊备受设计师的青睐,在各大知名APP中,如微信.手机QQ.网易云音乐等等都有对背景高斯图模糊的设计,在Adnroid 中,现在常用的图片高斯模糊 ...
- Android Bitmap转换WebP图片导致损坏的分析及解决方案
Android Bitmap转换WebP图片导致损坏的分析及解决方案 参考文章: (1)Android Bitmap转换WebP图片导致损坏的分析及解决方案 (2)https://www.cnblog ...
- Android bitmap图片处理
一.View转换为Bitmap 在Android中所有的控件都是View的直接子类或者间接子类,通过它们可以组成丰富的UI界面.在窗口显示的时候Android会把这些控件都加载到内存中 ...
- Android Bitmap 研究与思考(上篇)
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/107951273 本文出自[赵彦军的博客] 做Android 6年来,一直都没有对 ...
- Android—Bitmap图片大小计算、压缩与三级缓存
Bitmap对象占用内存大小: bitmap.getByteCount() 图片所占内存大小计算方式:图片长度 x 图片宽度 x 一个像素点占用的字节数. Android Bitmap使用的三种颜色格 ...
- android bitmap string,Android Bitmap到Base64字符串(Android Bitmap to Base64 String)
Android Bitmap到Base64字符串(Android Bitmap to Base64 String) 如何将一个大的Bitmap(用手机相机拍摄的照片)转换为Base64 String? ...
- Android Bitmap OutOfMemory 解决办法
Android Bitmap OutOfMemory 解决办法 置顶 2014年07月01日 14:41:22 阅读数:3072 标签: OutOfMemoryBitmapandroid图片优化更多 ...
最新文章
- ps -ef |grep 输出的具体含义
- python的应用领域有哪些、选择题_Python程序的设计复习题与答案
- hdu 1863(最小生成树kruskal)
- linux red hat 安装svn
- layui 在springboot2.x 时,页面展示不了layui的问题
- android tmp目录权限不够,/tmp目录下执行脚本失败提示Permission denied
- AgileEAS.NET SOA 中间件Web运行容器管理功能已全部开源,欢迎大家下载、使用、反馈...
- oracle 体系结构初步认识(一)
- ##R语言生信作图之UpsetR做交集图
- docker 基本指令
- Flutter 自定义CheckBox (用于兴趣爱好、风格选择)
- 阴历日期和阳历日期互相转换(java)
- 跨境电商ERP系统基础开发教程
- 虚拟机NAT模式的网络设置
- Diagrams(draw.io)-怎样实现跨线
- Java后端技术框架
- 用Selenium+xpath爬取京东商城
- 全球公认的最健康作息时间表(2015就照个来)
- layui 表无法渲染问题
- AHK 实现中英文输入法自由