Android Bitmap 模糊效果实现 (二)
文章目录
- Android Bitmap 模糊效果实现 (二)
- 使用 Vukan 模糊
- 使用 RenderEffect 模糊
- 使用 GLSL 模糊
- RS、Vukan、RenderEffect、GLSL 效率对比
Android Bitmap 模糊效果实现 (二)
本文首发地址 https://blog.csdn.net/CSqingchen/article/details/134656140
最新更新地址 https://gitee.com/chenjim/chenjimblog
通过 Android Bitmap 模糊效果实现 (一),我们知道可以使用 Toolkit 实现 Bitmap 模糊,还能达到不错的效果。本文主要讲解另外几种实现Bitmap模糊的方法并对比效率。
使用 Vukan 模糊
Vulkan 是一种低开销、跨平台的 API,用于高性能 3D 图形。
Android平台包含 Khronos Group 的 Vulkan API规范的特定实现。
Android Vulkan 使用可以参考:
https://developer.android.com/ndk/guides/graphics/getting-started
使用 Vukan 模糊的核心代码如下,可参考 ImageProcessor.cpp
bool ImageProcessor::blur(float radius, int outputIndex) {RET_CHECK(1.0f <= radius && radius <= 25.0f);// Calculate gaussian kernel, this is equivalent to ComputeGaussianWeights at// https://cs.android.com/android/platform/superproject/+/master:frameworks/rs/cpu_ref/rsCpuIntrinsicBlur.cpp;l=57constexpr float e = 2.718281828459045f;constexpr float pi = 3.1415926535897932f;float sigma = 0.4f * radius + 0.6f;float coeff1 = 1.0f / (std::sqrtf(2.0f * pi) * sigma);float coeff2 = -1.0f / (2.0f * sigma * sigma);int32_t iRadius = static_cast<int>(std::ceilf(radius));float normalizeFactor = 0.0f;for (int r = -iRadius; r <= iRadius; r++) {const float value = coeff1 * std::powf(e, coeff2 * static_cast<float>(r * r));mBlurData.kernel[r + iRadius] = value;normalizeFactor += value;}normalizeFactor = 1.0f / normalizeFactor;for (int r = -iRadius; r <= iRadius; r++) {mBlurData.kernel[r + iRadius] *= normalizeFactor;}RET_CHECK(mBlurUniformBuffer->copyFrom(&mBlurData));// Apply a two-pass blur algorithm: a horizontal blur kernel followed by a vertical// blur kernel. This is equivalent to, but more efficient than applying a 2D blur// filter in a single pass. The two-pass blur algorithm has two kernels, each of// time complexity O(iRadius), while the single-pass algorithm has only one kernel,// but the time complexity is O(iRadius^2).auto cmd = mCommandBuffer->handle();RET_CHECK(beginOneTimeCommandBuffer(cmd));// The temp image is used as an output storage image in the first pass.mTempImage->recordLayoutTransitionBarrier(cmd, VK_IMAGE_LAYOUT_GENERAL, /*preserveData=*/false);// First pass: apply a horizontal gaussian blur.mBlurHorizontalPipeline->recordComputeCommands(cmd, &iRadius, *mInputImage, *mTempImage,mBlurUniformBuffer.get());// The temp image is used as an input sampled image in the second pass,// and the staging image is used as an output storage image.mTempImage->recordLayoutTransitionBarrier(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);mStagingOutputImage->recordLayoutTransitionBarrier(cmd, VK_IMAGE_LAYOUT_GENERAL,/*preserveData=*/false);// Second pass: apply a vertical gaussian blur.mBlurVerticalPipeline->recordComputeCommands(cmd, &iRadius, *mTempImage, *mStagingOutputImage,mBlurUniformBuffer.get());// Prepare for image copying from the staging image to the output image.mStagingOutputImage->recordLayoutTransitionBarrier(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);// Copy staging image to output image.recordImageCopyingCommand(cmd, *mStagingOutputImage, *mOutputImages[outputIndex]);// Submit to queue.RET_CHECK(endAndSubmitCommandBuffer(cmd, mContext->queue()));return true;
}
Vukan 环境、资源、Pipeline 相关代码如下
https://github.com/android/renderscript-samples/tree/main/RenderScriptMigrationSample/app/src/main/cpp
上层接口参见 VulkanImageProcessor
这里需要用到 libVkLayer_khronos_validation.so, 可以在以下地址下载新版本
https://github.com/KhronosGroup/Vulkan-ValidationLayers
使用 RenderEffect 模糊
实现代码如下
override fun blur(radius: Float, outputIndex: Int): Bitmap {params?.let {val blurRenderEffect = RenderEffect.createBlurEffect(radius, radius,Shader.TileMode.MIRROR)return applyEffect(it, blurRenderEffect, outputIndex)}throw RuntimeException("Not configured!")
}
private fun applyEffect(it: Params, renderEffect: RenderEffect, outputIndex: Int): Bitmap {it.renderNode.setRenderEffect(renderEffect)val renderCanvas = it.renderNode.beginRecording()renderCanvas.drawBitmap(it.bitmap, 0f, 0f, null)it.renderNode.endRecording()it.hardwareRenderer.createRenderRequest().setWaitForPresent(true).syncAndDraw()val image = it.imageReader.acquireNextImage() ?: throw RuntimeException("No Image")val hardwareBuffer = image.hardwareBuffer ?: throw RuntimeException("No HardwareBuffer")val bitmap = Bitmap.wrapHardwareBuffer(hardwareBuffer, null)?: throw RuntimeException("Create Bitmap Failed")hardwareBuffer.close()image.close()return bitmap
}
inner class Params(val bitmap: Bitmap, numberOfOutputImages: Int) {@SuppressLint("WrongConstant")val imageReader = ImageReader.newInstance(bitmap.width, bitmap.height,PixelFormat.RGBA_8888, numberOfOutputImages,HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or HardwareBuffer.USAGE_GPU_COLOR_OUTPUT)val renderNode = RenderNode("RenderEffect")val hardwareRenderer = HardwareRenderer()init {hardwareRenderer.setSurface(imageReader.surface)hardwareRenderer.setContentRoot(renderNode)renderNode.setPosition(0, 0, imageReader.width, imageReader.height)}
}
完整实例参考
RenderEffectImageProcessor.kt
使用 GLSL 模糊
主要流程:
- 将输入 Bitmap 转为纹理
GLES31.glTexStorage2D( GLES31.GL_TEXTURE_2D, 1, GLES31.GL_RGBA8, mInputImage.width, mInputImage.height ) - 通过 OpenGL 处理纹理
完整实例参考 GLSLImageProcessor.kt
RS、Vukan、RenderEffect、GLSL 效率对比
通过示例 RenderScriptMigrationSample 可以看到
他们之间效率对比结果如下

以上就是 Bitmap 模糊实现的方案二,希望对你有所帮助。
如果你在使用过程遇到问题,可以留言讨论。
如果你觉得本文写的还不错,欢迎点赞收藏。
相关文章
Android Bitmap 模糊效果实现 (一)
Android Bitmap 模糊效果实现 (二)
相关文章:
Android Bitmap 模糊效果实现 (二)
文章目录 Android Bitmap 模糊效果实现 (二)使用 Vukan 模糊使用 RenderEffect 模糊使用 GLSL 模糊RS、Vukan、RenderEffect、GLSL 效率对比 Android Bitmap 模糊效果实现 (二) 本文首发地址 https://blog.csdn.net/CSqingchen/article/details/134656140 最新更新地址 https:/…...
初识Java 18-4 泛型
目录 泛型存在的问题 在泛型中使用基本类型 实现参数化接口 类型转换和警告 无法实现的重载 基类会劫持接口 自限定类型 奇异递归类型 自限定 自限定提供的参数协变性 本笔记参考自: 《On Java 中文版》 泛型存在的问题 接下来讨论的,是在泛型…...
家政保洁预约小程序app开发特点有哪些?
家政预约服务小程序APP开发的特点介绍; 1. 低成本:用户通过手机APP下单,省去了中介费用,降低了雇主的雇佣成本。 2. 高收入:家政服务人员通过手机APP接单,省去了中介费用,从而提高了服务人员的…...
【JavaEE初阶】 HTTP响应报文
文章目录 🌲序言🎍200 OK🍀404 Not Found🎄403 Forbidden🌴405 Method Not Allowed🎋500 Internal Server Error🌳504 Gateway Timeout🌲302 Move temporarily🎍301 Move…...
PTA: 螺旋矩阵
题目 所谓“螺旋矩阵”,是指对任意给定的N,将1到NN的数字从左上角第1个格子开始,按顺时针螺旋方向顺序填入NN的方阵里。本题要求构造这样的螺旋方阵。 格式 输入格式: 输入在一行中给出一个正整数N(<10)。 输出…...
SparkSQL远程调试(IDEA)
启动Intellij IDEA,打开spark源码项目,配置远程调试 Run->Edit Configuration 启动远程spark-sql spark-sql --verbose --driver-java-options "-Xdebug -Xrunjdwp:transportdt_socket,servery,suspendy,address5005"运行远程调试…...
Vue2 Vue3 响应式实现原理
Vue2 和 Vue3 的响应式实现原理有所不同。 Vue2 响应式实现原理: Vue2 使用 Object.defineProperty() 方法来实现数据劫持,从而实现数据的响应式更新。具体步骤如下: 首先,在初始化阶段,遍历 data 对象的所有属性&a…...
Android Tombstone 与Debuggerd 原理浅谈
一、前言 Android系统类问题主要有stability、performance、power、security。tombstoned是android平台的一个守护进程,它注册成3个socket服务端,客户端封装在crash_dump和debuggerd_client。 crash_dump用于跟踪定位C crash, debuggerd_cli…...
Matlab 三维电力线重建
文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 之前曾经讨论过关于悬链线方程的曲线拟合点云最小二乘法拟合曲线,在这篇博客中其实拟合的是悬链线的一种近似形式,但对于大多数情况下已经够用了。方程如下所示: z = A ( x 2 + y 2 ) +...
GoLang Filepath.Walk遍历优化
原生标准库在文件量过大时效率和内存均表现不好 1400万文件遍历Filepath.Walk 1400万文件重写直接调用windows api并处理细节 结论 1400万文件遍历时对比 对比条目filepath.walkwindows api并触发黑科技运行时间710秒22秒内存占用480M38M 关键代码 //超级快的文件遍历 fun…...
Java面向对象第7天
精华笔记: 成员内部类:了解,应用率不高 类中套类,外面的称为外部类,里面的称为内部类 内部类只服务于外部类,对外不具备可见性 内部类对象通常在外部类中创建 内部类中可以直接访问外部类的成员(包括私有…...
网络安全如何自学?
1.网络安全是什么 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高; 二、则是发展相对成熟…...
Flink-时间窗口
在流数据处理应用中,一个很重要、也很常见的操作就是窗口计算。所谓的“窗口”,一 般就是划定的一段时间范围,也就是“时间窗”;对在这范围内的数据进行处理,就是所谓的 窗口计算。所以窗口和时间往往是分不开的。 时…...
软件设计模式原则(三)单一职责原则
单一职责原则(SRP)又称单一功能原则。它规定一个类应该只有一个发生变化的原因。所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原…...
使用Postman创建Mock Server
这篇文章将教会大家如何利用 Postman,通过 Mock 的方式测试我们的 API。 什么是 Mock Mock 是一项特殊的测试技巧,可以在没有依赖项的情况下进行单元测试。通常情况下,Mock 与其他方法的主要区别就是,用于取代代码依赖项的模拟对…...
【古月居《ros入门21讲》学习笔记】15_ROS中的坐标系管理系统
目录 说明: 1. 机器人中的坐标变换 tf功能包能干什么? tf坐标变换如何实现 2. 小海龟跟随实验 安装 ros-melodic-turtle-tf 实验命令 运行效果 说明: 1. 本系列学习笔记基于B站:古月居《ROS入门21讲》课程,且使…...
初始linux:文件操作
目录 提示:以下指令均在Xshell 7 中进行 linux的理念 一、echo echo "字符串" 二、输出重定向 > > [文件] echo "字符串" > [文件] echo "字符串" > > [文件] 制作大文件 三、< 输入重定向与ca…...
iOS上传ipa使用可视化工具Transporter
文章目录 前言一、Transporter二、Appuploader三、iTMSTransporter总结 前言 最近为了让非开发人员上传IPA文件,特意找了一些方法,至于以前的ApplicationUploader已经不能用了,下面介绍两个工具可以上传IPA包。 一、Transporter 1、操作简单…...
解读《陆奇最新演讲实录—我的大模型世界观》
腾讯科技频道记者张小珺一篇《陆奇最新演讲实录—我的大模型世界观》刷爆朋友圈。文章知识点丰富、字里行间处处流淌着创业方法论和AI应用商机,含金量极高! PS:一家之言、不求苟同。如有不爽之处,欢迎来 找我。 腾讯新闻原文&am…...
ChatGPT到底是如何运作?
自从2022年11月30日发布以来,ChatGPT一直占据着科技届的头条位置,随着苹果的创新能力下降,ChatGPT不断给大家带来震撼,2023年11月7日,首届OpenAI开发者大会在洛杉矶举行,业界普遍认为,OpenAI的开…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
