前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >如何使用 RenderScript实现抖音的黑金效果

如何使用 RenderScript实现抖音的黑金效果

作者头像
xiangzhihong
发布于 2022-11-30 08:06:38
发布于 2022-11-30 08:06:38
95800
代码可运行
举报
文章被收录于专栏:向治洪向治洪
运行总次数:0
代码可运行

最近,有人问我一个问题,如何使用彩图转为黑白,又如何将黑白图片转换为彩图?对于这个问题,我能想到的最直接的方法是:调用Android的系统Api获取图片生成bitmap文件,然后再使用Android中的二值化技术即可实现;除此之外,还可以使用FFpeg等库的方式实现。不过,我们今天要讲的是另外一种方案,即使用RenderScript方式。

一、RenderScript简介

RenderScript 是用于在 Android 上以高性能运行计算密集型任务的框架。RenderScript 专为数据并行计算而设计,不过串行工作负载也可以从中受益。RenderScript 运行时可以并行安排设备上可用的多个处理器(如多核 CPU 和 GPU)上的工作负载,使开发者能够专注于表达算法而不是调度工作。RenderScript 对于专注于图像处理、计算摄影或计算机视觉的应用来说尤其有用。

RenderScript使用的是一种类似于C/C++的rs 脚本语法,且是在运行时编译、跨平台的。性能比 Java 好,比 Native 略差。下图是RenderScript在Android 8.0 及更高版本的设备上的一个框架示意图。

与 Android 7.x 及更低版本中的 RenderScript 之间的区别如下:

  • 一个进程中有两组 RenderScript 内部库的实例。一组用于 CPU 备用路径,直接来源于 /system/lib;另一组用于 GPU 路径,来源于 /system/lib/vndk-sp。
  • /system/lib 中的 RS 内部库是作为平台的一部分构建的,会随着 system.img 的升级而更新。不过,/system/lib/vndk-sp 中的库是面向供应商构建的,不会随着 system.img 的升级而更新(虽然可以针对安全修复程序进行更新,但其 ABI 仍然保持不变)。
  • 供应商代码(RS HAL、RS 驱动程序和 bcc plugin)与位于 /system/lib/vndk-sp 的 RenderScript 内部库相关联。它们无法与 /system/lib 中的库相关联,因为该目录中的库是面向平台构建的,可能与供应商代码不兼容(即,符号可能会被移除)。如此一来可能会导致仅针对框架的 OTA 无法实现。

关于RenderScript的说明,可以参考RenderScript架构组成

二、RenderScript使用

RenderScript的使用分为两个步骤:

  1. 编写 .rs 内核脚本文件;
  2. 使用编写的文件进行渲染方面的处理;

2.1 编写内核脚本文件

RenderScript 内核通常位于 <project_root>/src/ 目录下,由类C语言的.rs语法编写,每个.rs 文件就是一个脚本,每个脚本由一组内核、函数和变量构成。首先,创建一个rs脚本文件代码。 在这里插入图片描述

然后,打开 app 的 build.gradle 文件,在 android 的 defaultConfig 结点添加两句:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
renderscriptTargetApi 18
renderscriptSupportModeEnabled true

接下来,下面以【将图片置灰】为例来说明如何编写内核脚本文件,新建一个 Gray.rs 文件,如下所示。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma version(1)
#pragma rs java_package_name(com.avatar.rs)

void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
    // a 是透明度,这里不修改透明度。
    out->a = in->a;

    // 快,但并不是真正意义的去色
    out->r = out->g = out->b = (in->r + in->g + in->b) / 3;

    // 慢,但是是真正的去色
    // out->r = out->g = out->b = (in->r * 299 + in->g * 587 + in->b * 114 + 500) / 1000;
}

void init() {
}

其中,第1行声明 RenderScript 的版本;第2行是申明该脚本所在的Java包的包名;root 函数是脚本文件的入口函数,对于图片来说,root函数负责对每一个像素做处理。参数 in 是输入像素点的指针; out 是输出像素点的指针。并且,init 函数是可选的,主要用于做一些初始化的工作。

2.2 调用rs脚步文件

使用前,需要先引入RenderScript脚本文件,如下所示。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import com.avatar.rs.ScriptC_greyscale;

这里的类名是 ScriptC_ 加上 .rs 的文件名,包名就是在创建 rs 文件时声明的包名。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import com.avatar.rs.ScriptC_greyscale;

public class MainActivity extends AppCompatActivity {

    private ImageView mImageView;
    private ImageView mRSImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mImageView =  findViewById(R.id.image_view);
        mRSImageView =  findViewById(R.id.rs_image_view);

        Bitmap mInBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test);
        Bitmap  mOutBitmap = Bitmap.createBitmap(mInBitmap.getWidth(), mInBitmap.getHeight(), mInBitmap.getConfig());
        mImageView.setImageBitmap(mInBitmap);

        Bitmap bitmap=transGray(this,mInBitmap);
        mRSImageView.setImageBitmap(bitmap);
    }


    public static Bitmap transGray(@NonNull Context context, @NonNull Bitmap bitmap) {
        // 创建输出 bitmap
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Bitmap outBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        // 创建 RenderScript 对象
        RenderScript rs = RenderScript.create(context);
        // 创建输入、输出 Allocation
        Allocation allIn  = Allocation.createFromBitmap(rs, bitmap);
        Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);
        // 创建我们在上面定义的 script
        ScriptC_greyscale script = new ScriptC_greyscale(rs);
        // 对每一个像素执行 root 方法
        script.forEach_root(allIn, allOut);
        // 将执行结果复制到输出 bitmap 上
        // 释放资源
        rs.destroy();
        return outBitmap;
    }
}

然后,我们运行下代码,看看前后的对比效果。

2.3 多函数调用

除了 root 函数,我们还可以在 .rs 中定义其他的 kernal 函数,比如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** 
 * 黑金色转换
 */
uchar4 __attribute__((kernel)) blackGold(uchar4 in, uint32_t x, uint32_t y) {
    uchar4 out = in;

    if ((in.r < in.b) && (in.g < in.b)) {
        out.r = out.g = out.b = (in.r*299 + in.g*587 + in.b*114 + 500) / 1000;
    }

    return out;
}


uchar4 __attribute__((kernel)) root(uchar4 v_in) {
    float4 f4 = rsUnpackColor8888(v_in);

    float3 mono = dot(f4.rgb, gMonoMult);
    return rsPackColorTo8888(mono);
}

uchar __attribute__((kernel)) toU8(uchar4 v_in) {
    float4 f4 = convert_float4(v_in);
    return (uchar)dot(f4.rgb, gMonoMult);
}

uchar4 __attribute__((kernel)) toU8_4(uchar v_in) {
    return (uchar4)v_in;
}

在定义kernal 函数时,函数返回值必须是 uchar4, 并且用 __attribute__((kernel)) 标记该函数是个 kernal 函数。然后,我们在Java代码中就可以使用下面的方式进行调用了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
script.forEach_blackGold(allIn, allOut);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-09-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android Renderscript(一)
渲染脚本(Renderscript)提供用C语言(C99标准)编写的原生级高性能的计算API。Renderscript 让你的应用程序有能力跨越所有可用的处理器内核来自动的平行的运行各种操作。它还提供了对不同类型 的处理的支持,如CPU、GPU或DSP等。Renderscript对于图形处理、数学模型或其他任何需要大量的数 学计算的应用程序都使用有用的。
用户3004328
2018/09/06
1.6K0
Android Renderscript(一)
Android Studio 2.2 JNI编译及Rxjava使用初级背景
jni-2.png 背景 最近几天刚好无事由于在新公司,业务上安排不是很满。android studio 2.2以后,jni比较方便开发了。本文是使用jni进行初级的demo需求。一个图片的高斯模糊效果。算法参见(https://github.com/GankLi/Demo/tree/demo/app/src/main/java/com/gank/demo/gaussblurtest)。 上图是未模糊前原图,恩,我会把它模糊滴。 前提 请下下好ndk和cmake工具。需要环境android studio 2
用户1127566
2018/06/04
7130
Android 图片功能模块相关库
If you want to let your users choose crop ratio dynamically, just do not call withAspectRatio(x, y).
用户3004328
2018/09/06
1.3K0
Android 图片功能模块相关库
Android内存缓存:手把手教你学会LrhCache算法
当 accessOrder 参数设置为true时,存储顺序(遍历顺序) = 外部访问顺序
Carson.Ho
2022/03/25
4440
Android内存缓存:手把手教你学会LrhCache算法
android 高斯模糊实现
高斯模糊 高斯模糊就是将指定像素变换为其与周边像素加权平均后的值,权重就是高斯分布函数计算出来的值。 一种实现 点击打开链接<-这里是一片关于高斯模糊算法的介绍,我们需要首先根据高斯分布函数计算权重值,为了提高效率我们采用一维高斯分布函数,然后处理图像的时候在横向和纵向进行两次计算得到结果。下面是一种实现 public static void gaussBlur(int[] data, int width, int height, int radius,   float sigma) {  
xiangzhihong
2018/02/01
1.5K0
android 高斯模糊实现
Android实现Bitmap高斯模糊效果
Android实现Bitmap高斯模糊效果 自定义高斯模糊工具类 import android.content.Context; import android.graphics.Bitmap; import android.renderscript.Allocation; import android.renderscript.Element; import android.renderscript.RenderScript; import android.renderscript.ScriptIntrin
程序员飞飞
2020/02/27
1.6K0
1-MI-Android多媒体之Bitmap
张风捷特烈个人网站,编程笔记请访问:http://www.toly1994.com
张风捷特烈
2018/09/04
6170
1-MI-Android多媒体之Bitmap
1-MI-Android多媒体之Bitmap
零、前言 [1].Bitmap是关于图象的类,也就是位图 [2].生成Bitmap对象的方式 [3].BitmapFactory.Options [4].模糊处理 [5].给一个Bitmap添加倒影 [6].将一个View转换成Bitmap [7].保存bitmap ---- 一、生成Bitmap对象的方式 1.从文件获取(运行时权限自己处理) //通过文件绝对路径加载图片 Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/DCIM
张风捷特烈
2018/09/29
5670
1-MI-Android多媒体之Bitmap
开源框架之[-Picasso-]应用篇
零、前言 Picasso是一个图片加载的框架,内部依赖了OkHttp,OkHttp内部依赖了okio 依赖:implementation 'com.squareup.picasso:picasso:2.71828' 本篇讲一下Picasso的用法,下一篇分析一下Picasso的源码 picasso.png ---- 一、Picasso的缓存相关 Picasso.get().setIndicatorsEnabled(true); |--标记处图片加载的位置 |
张风捷特烈
2019/03/04
6810
开源框架之[-Picasso-]应用篇
高斯模糊效果的几种实现方案及性能对比
本文介绍了如何利用RenderScript实现高斯模糊,以及如何使用FastBlur在Android平台上实现类似效果。通过比较不同方案在处理速度、效果、性能上的差异,为你在实现类似功能时提供有价值的参考。同时,也提醒开发者在选择方案时要根据具体业务需求来灵活选择。
胡力
2017/10/17
5.6K3
高斯模糊效果的几种实现方案及性能对比
Java实现高斯模糊和图像的空间卷积
其中r是模糊半径,r^2 = x^2 + y^2,σ是正态分布的标准偏差。在二维空间中,这个公式生成的曲面的等高线是从中心开始呈正态分布的同心圆。分布不为零的像素组成的卷积矩阵与原始图像做变换。每个像素的值都是周围相邻像素值的加权平均。原始像素的值有最大的高斯分布值,所以有最大的权重,相邻像素随着距离原始像素越来越远,其权重也越来越小。这样进行模糊处理比其它的均衡模糊滤波器更高地保留了边缘效果。
fengzhizi715
2018/08/24
1.5K0
Java实现高斯模糊和图像的空间卷积
Android如何实现毛玻璃效果之Android高级模糊技术
Android高级模糊技术 非著名程序员 自从iOS系统引入了Blur效果,也就是所谓的毛玻璃、模糊化效果,磨砂效果,各大系统就开始竞相模仿,这是怎样的一个效果呢,我们先来看一下,如下面的图片:
非著名程序员
2018/02/01
3K0
Android如何实现毛玻璃效果之Android高级模糊技术
探索Camera ImageReader YUV420_888 快速转bitmap argb888的方式
不过这篇文件还是介绍RenderScript 的使用,RenderScript 相对比较简单一些。
小驰行动派
2024/05/27
4921
探索Camera ImageReader YUV420_888 快速转bitmap argb888的方式
NDK开发(八) :JNI下Bitmap的使用
NDK 已经为我们准备好了操作 Bitmap 的相关头文件了,它就是 <android/bitmap.h>。
103style
2022/12/19
8540
Bitmap 详解
Bitmap在Android中指的是一张图片,可以是png,也可以是jpg等其他图片格式。
Yif
2020/04/23
2.1K0
Bitmap 详解
Android JNI 之 Bitmap 操作
在 Android 通过 JNI 去调用 Bitmap,通过 CMake 去编 so 动态链接库的话,需要添加 jnigraphics 图像库。
音视频开发进阶
2019/07/26
3.3K0
Android TabLayout 使用进阶(含源码)
  对于Android开发来说,画页面算是必不可少的,因此你会接触很多不同的UI布局,你需要去绘制出来,在这过程中你已经接触过TabLayout。
晨曦_LLW
2021/05/06
3.2K2
相关推荐
Android Renderscript(一)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文