Android Bitmap 使用Vukan、RenderEffect、GLSL实现模糊

文章目录

  • Android Bitmap 使用Vukan、RenderEffect、GLSL实现模糊
      • 使用 RenderEffect 模糊
      • 使用 Vukan 模糊
      • 使用 GLSL 模糊
      • RS、Vukan、RenderEffect、GLSL 效率对比

Android Bitmap 使用Vukan、RenderEffect、GLSL实现模糊

本文首发地址 https://blog.csdn.net/CSqingchen/article/details/134656140
最新更新地址 https://gitee.com/chenjim/chenjimblog

通过 Android Bitmap 使用 ScriptIntrinsicBlur、Toolkit 实现模糊,我们已经知道两种实现模糊方法。
本文主要讲解另外几种高效实现Bitmap模糊的方法。

使用 RenderEffect 模糊

RenderEffect 是 Android 中一种用于实现图像特效的类,**最低 API 要求 31 ** 。
它允许开发者在不修改原始图像数据的情况下,对图像进行各种处理,例如模糊、光晕、阴影等
对 Bitmap 模糊及注释代码如下

fun blur(bitmap:Bitmap, radius: Float, outputIndex: Int): Bitmap {

     // 配置跟 bitmap 同样大小的 ImageReader
    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()

    // 将 ImageReader 的surface 设置到 HardwareRenderer 中
    hardwareRenderer.setSurface(imageReader.surface)
    hardwareRenderer.setContentRoot(renderNode)
    renderNode.setPosition(0, 0, imageReader.width, imageReader.height)

    // 使用 RenderEffect 配置模糊效果,并设置到 RenderNode 中。  
    val blurRenderEffect = RenderEffect.createBlurEffect(
        radius, radius,
        Shader.TileMode.MIRROR
    )
    renderNode.setRenderEffect(renderEffect)

    // 通过 RenderNode 的 RenderCanvas 绘制 Bitmap。   
    val renderCanvas = renderNode.beginRecording()
    renderCanvas.drawBitmap(bitmap, 0f, 0f, null)
    renderNode.endRecording()

    // 通过 HardwareRenderer 创建 Render 异步请求。   
    hardwareRenderer.createRenderRequest()
        .setWaitForPresent(true)
        .syncAndDraw()

    // 通过 ImageReader 获取模糊后的 Image 。
    val image = imageReader.acquireNextImage() ?: throw RuntimeException("No Image")

    // 将 Image 的 HardwareBuffer 包装为 Bitmap , 也就是模糊后的。   
    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
}

完整实例参考 RenderEffectImageProcessor.kt
还可以通过设置 RenderEffect 的其他属性,如 setColorFilter( )方法,为模糊后的 Bitmap 添加颜色滤镜。

使用 Vukan 模糊

Vulkan 是一种低开销、跨平台的 API,用于高性能 3D 图形。
Android平台包含 Khronos Group 的 Vulkan API规范的特定实现。
使用 Vukan 模糊的核心代码如下,可参考 ImageProcessor.cpp

bool ImageProcessor::blur(float radius, int outputIndex) {
    RET_CHECK(1.0f <= radius && radius <= 25.0f);

    //高斯模糊配置,在后文 GLSL 同样 适用
    constexpr 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));

    // 应用两阶段模糊算法:一个水平模糊核,然后是一个垂直模糊核。
    // 比单遍应用一个2D模糊滤镜更高效。
    // 两遍模糊算法有两个核,每个核的时间复杂度为O(半径),
    // 而单遍模糊算法只有一个核,但时间复杂度为O(半径^2)。
    auto cmd = mCommandBuffer->handle();
    RET_CHECK(beginOneTimeCommandBuffer(cmd));

    // 临时映像在第一遍中用作输出存储映像
    mTempImage->recordLayoutTransitionBarrier(cmd, VK_IMAGE_LAYOUT_GENERAL, /*preserveData=*/false);

    // 水平方向高斯模糊
    mBlurHorizontalPipeline->recordComputeCommands(cmd, &iRadius, *mInputImage, *mTempImage,
                                                   mBlurUniformBuffer.get());

    // 临时图像在第二遍中用作输入采样图像,
    // 过渡图像用作输出存储映像。
    mTempImage->recordLayoutTransitionBarrier(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
    mStagingOutputImage->recordLayoutTransitionBarrier(cmd, VK_IMAGE_LAYOUT_GENERAL,
                                                       /*preserveData=*/false);

    // 数值方向高斯模糊
    mBlurVerticalPipeline->recordComputeCommands(cmd, &iRadius, *mTempImage, *mStagingOutputImage,
                                                 mBlurUniformBuffer.get());

    // 准备将图像从过渡图像复制到输出图像。
    mStagingOutputImage->recordLayoutTransitionBarrier(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);

    // 复制暂存图像到输出图像。
    recordImageCopyingCommand(cmd, *mStagingOutputImage, *mOutputImages[outputIndex]);

    // 提交到队列。
    RET_CHECK(endAndSubmitCommandBuffer(cmd, mContext->queue()));
    return true;
}

VulkanContext.cpp 主要是一些初始化

VulkanResources.cpp 主要是 Buffer 和 Image 的一些封装方法

上层接口参见 VulkanImageProcessor.kt

使用 GLSL 模糊

主要流程:

  • 将输入 Bitmap 转为纹理
    GLES31.glTexStorage2D(GLES31.GL_TEXTURE_2D, 1, GLES31.GL_RGBA8, mInputImage.width, mInputImage.height )
    GLUtils.texImage2D(GLES31.GL_TEXTURE_2D, 0, mInputImage, 0)
  • 通过 OpenGL 处理纹理,同样有水平、竖直模糊,即 mBlurHorizontalProgram 和 mBlurVerticalProgram
  • 将纹理转换为 Bitmap ,即 copyPixelsToHardwareBuffer ,这里也是耗时最多的

完整实例参考 GLSLImageProcessor.kt

libVkLayer_khronos_validation.so 主要是调试用,
ImageProcessor::create(/*enableDebug=*/false, assetManager) 传入 false 可以不需要
可以在以下地址下载新版本
https://github.com/KhronosGroup/Vulkan-ValidationLayers

RS、Vukan、RenderEffect、GLSL 效率对比

上文完整源码及对比示例地址
https://gitee.com/chenjim/android-blur/blob/blur/RenderScriptMigrationSample

他们之间效率对比结果如下

虽然 GLSL 看起来会差一些,主要是因为 openGL 纹理转 Bitmap 耗时较大。
如果纯GL场景使用,跟 Vukan 和 RenderEffect 相差无几。


以上就是Android 使用Vukan、RenderEffect、GLSL实现模糊的介绍,希望对你有所帮助。
如果你在使用过程遇到问题,可以留言讨论。
如果你觉得本文写的还不错,欢迎点赞收藏。


相关文章
Android Bitmap 使用ScriptIntrinsicBlur、Toolkit 实现模糊
Android Bitmap 使用Vukan、RenderEffect、GLSL实现模糊)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/209334.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

行内元素和块级元素分别有哪些?有何区别?怎样转换?

行内元素和块级元素分别有哪些&#xff1f; 常见的块级元素&#xff1a; p、div、form、ul、li、ol、table、h1、h2、h3、h4、h5、h6、dl、dt、dd 常见的行级元素&#xff1a; span、a、img、button、input、select 有何区别&#xff1f; 块级元素&#xff1a; 总是在新行上…

Centos7安装

想学Vmware安装可以看下下面链接,不想就算了 https://blog.csdn.net/weixin_43895362/article/details/134723073 选择第一项&#xff0c;安装直接CentOS 7&#xff0c;回车 稍等后出现进入下图,选择中文,这个只是安装时的语言 首先设置时间,时区选择上海&#xff0c;查看时…

JVM 类的加载

面试题&#xff1a; 简述 Java 类加载机制?&#xff08;百度&#xff09; JVM类加载机制 &#xff08;滴滴&#xff09; JVM中类加载机制&#xff0c;类加载过程&#xff0c;什么是双亲委派模型&#xff1f; &#xff08;腾讯&#xff09; JVM的类加…

【UE】射线检测与物品高亮显示

效果 步骤 1. 新建一个空白模板工程 2. 添加一个第一人称游戏内容包 3. 打开项目设置&#xff0c;创建一个新的通道检测 取消勾选“自动曝光” 4. 打开第一人称角色蓝图“BP_FirstPersonCharacter”&#xff0c;添加一个新图表&#xff0c;命名为“射线检测” 添加如下节点&a…

LeNet对MNIST 数据集中的图像进行分类--keras实现

我们将训练一个卷积神经网络来对 MNIST 数据库中的图像进行分类&#xff0c;可以与前面所提到的CNN实现对比CNN对 MNIST 数据库中的图像进行分类-CSDN博客 加载 MNIST 数据库 MNIST 是机器学习领域最著名的数据集之一。 它有 70,000 张手写数字图像 - 下载非常简单 - 图像尺…

CMMI认证含金量高吗

一、CMMI认证含金量解答 CMMI&#xff0c;即能力成熟度模型集成&#xff0c;是由美国卡内基梅隆大学软件工程研究所开发的一种评估企业软件开发过程成熟度的模型。CMMI认证的含金量究竟高不高呢&#xff1f;答案是肯定的。CMMI认证被誉为软件开发行业的“金牌标准”&#xff0…

vue循环v-for遍历图表

循环遍历图表 index.vue主页面 <view v-if"powerPage"><view v-for"(item, index) in powerDetailsData.addMap" :key"index"><PowerEChartsCity:echartData"powerDetailsData.addMap[index]"></PowerEChartsC…

经典神经网络——VGGNet模型论文详解及代码复现

论文地址&#xff1a;1409.1556.pdf。 (arxiv.org)&#xff1b;1409.1556.pdf (arxiv.org) 项目地址&#xff1a;Kaggle Code 一、背景 ImageNet Large Scale Visual Recognition Challenge 是李飞飞等人于2010年创办的图像识别挑战赛&#xff0c;自2010起连续举办8年&#xf…

Unity 关于SpriteRenderer 和正交相机缩放

float oldWidth 750f;float oldHeight 1334f;float newWidth Screen.width;float newHeight Screen.height;float oldAspect oldWidth / oldHeight;float newAspect newWidth / newHeight;//水平方向缩放float horizontalCompressionRatio newAspect / oldAspect;//垂直…

Python 中的 FileSystem Connector:打通文件系统的便捷通道

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是涛哥&#xff0c;今天为大家分享 Python 中的 FileSystem Connector&#xff1a;打通文件系统的便捷通道&#xff0c;全文4100字&#xff0c;阅读大约11分钟。 在现代软件开发中&#xff0c;文件系统是不可或…

【Python表白系列】一起去看流星雨吧!(完整代码)

文章目录 流星雨环境需求完整代码详细分析系列文章流星雨 环境需求 python3.11.4PyCharm Community Edition 2023.2.5pyinstaller6.2.0(可选,这个库用于打包,使程序没有python环境也可以运行,如果想发给好朋友的话需要这个库哦~)【注】 python环境搭建请见:https://want5…

数据结构算法-选择排序算法

引言 说起排序算法&#xff0c;那可就多了去&#xff0c;首先了解什么叫排序 以B站为例&#xff1a; 蔡徐坤在B站很受欢迎呀&#xff0c;先来看一下综合排序 就是播放量和弹幕量&#xff0c;收藏量 一键三连 都很高这是通过一些排序算法 才能体现出综合排序 蔡徐坤鬼畜 按照播…

flutter-一个可以输入的数字增减器

效果 参考文章 代码 在参考文章上边&#xff0c;主要是改了一下样式&#xff0c;逻辑也比较清楚&#xff0c;对左右两边添加增减方法。 我在此基础上加了_numcontroller 输入框的监听。 加了数字输入框的控制 keyboardType: TextInputType.number, //设置键盘为数字 inputF…

异常处理啊

异常处理 异常 程序运行过程中&#xff0c;发生错误导致异常退出&#xff08;不是程序的语法问题&#xff0c;而是代码的逻辑问题&#xff0c;编译不出错&#xff09;。 e.g. string 字符串&#xff0c;使用 at 函数访问其中的字符元素时&#xff0c;如果越界&#xff0c;程…

Next.js初步使用

文章目录 安装和运行页面静态文件 React初步&#xff0c;但不熟悉React也可以学习本文。 安装和运行 Next.js是一个基于React的服务端渲染框架&#xff0c;可以实现构建高性能、可扩展的React应用&#xff0c;提供了很多方便的工具和功能&#xff0c;包括自动代码分割、服务器…

rdf-file:SM2加解密

一&#xff1a;SM2简介 SM2是中国密码学算法标准中的一种非对称加密算法&#xff08;包括公钥和私钥&#xff09;。SM2主要用于数字签名、密钥交换和加密解密等密码学。 生成秘钥&#xff1a;用于生成一对公钥和私钥。公钥&#xff1a;用于加密数据和验证数字签名。私钥&…

【代码】两阶段鲁棒优化/微电网经济调度入门到编程

内容包括 matlab-yalmipcplex微电网两阶段鲁棒经济调度&#xff08;刘&#xff09; matlab-yalmipcplex两阶段鲁棒微电网容量经济优化调度 两阶段鲁棒优化CCG列于约束生成和Benders代码&#xff0c;可扩展改编&#xff0c;复现自原外文论文 【赠送】虚拟储能单元电动汽车建…

【二叉树】常见题目解析(2)

题目1&#xff1a;104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 题目1描述&#xff1a; 题目1分析及解决&#xff1a; &#xff08;1&#xff09;base case&#xff1a;当前节点为null时&#xff0c;以当前节点为根节点的树最大深度是0。 &#xff08;2&…

【C/PTA —— 13.指针2(课外实践)】

C/PTA —— 13.指针2&#xff08;课外实践&#xff09; 一.函数题6-1 鸡兔同笼问题6-2 冒泡排序6-3 字符串反正序连接6-4 计算最长的字符串长度6-5 查找星期 二.编程题7-1 C程序设计 实验5-7 数组指针作函数参数7-2 查找奥运五环色的位置 一.函数题 6-1 鸡兔同笼问题 int Chic…

Nginx反向代理详解

Nginx反向代理详解 nginx反向代理是一种常用的服务器架构设计方案&#xff0c;其原理是将客户端请求先发送到反向代理服务器&#xff0c;反向代理服务器再将请求转发到后端真实服务器处理&#xff0c;并将处理结果返回给客户端&#xff0c;从而实现负载均衡、高可用、安全和减…