Android RenderScript实现LowPoly效果

2024-03-16 02:10

本文主要是介绍Android RenderScript实现LowPoly效果,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今日科技快讯

近日,利用银行新规的诈骗手法已出现,大家要注意了!根据银行新规,在ATM机上转账时,除同行同户名的卡,其他均在24小时后才能到账,且24小时内可撤销转账!不法分子以“先转账、再取现”骗取受害者信任,在拿到现金后,便会前往柜台撤销转账!

有网友爆料称,前天一个陌生电话打来订货,不说要什么就说配5000块的货,发了ATM转账凭证过来,然后就不停催发货,打银行客服查询确实有这交易,不过还是多了心眼没发货,到今天了24小时钱也没到账,银行查询是该笔交易已撤销。

作者简介

新的一周开始了,又到了跟大家见面的时候!本篇是 reikyZ 的第二篇投稿,本文包含基本概念的讲解以及RenderScript的基本使用。如果看了本文对这个知识感兴趣的朋友可以访问作者博客,进行更深入的了解。

reikyZ 的博客地址:

http://www.jianshu.com/users/5bf423bcdb88

前言

之前在知乎看到一篇关于 LowPoly  js 实现的贴:

https://www.zhihu.com/question/29856775

觉得效果很棒,就打算在 Android 上实现看看。本来以为一两天就可以搞定,没想到不知不觉耗了一周多,踏坑不少。鉴于内容可能会比较多,所以暂时打算分篇幅介绍实现过程。

LowPoly (低多边形) 这种风格在前两年十分风靡,比较有名的《纪念碑谷》就是采用这种美术风格的游戏。

纪念碑谷

效果

LowPolyAndroid

https://github.com/zzhoujay/LowPolyAndroid

java cost time

这个是由 纯 java 实现的版本,在查找资料时找到的,应该是国内某人写的。用 Nexus5 测试,处理尺寸为 900 * 900 的 bitmap 图片耗时基本在 60~90 s 左右,可见效率确实比较不能忍受。从 Log 的计时器看,在处理两千不到的取样点的情况下,三角化和绘图耗时都在 1s 以内,所以估计主要耗时应该在 Sobel 边缘处理和点列采样的过程中,没有验证,有心的同学可以试试看。需要说明的是,我的实现使用了这位同学的 Delaunay 算法和 canvas 部分的代码(表示感谢!),所以在取样点差不多时,我的效果应该和这个差不多。

LowPoly

https://github.com/CoXier/LowPoly

jni cost time

这个是国外某位使用 jni 实现的版本,是在着手写该篇时才找到的,看到其介绍由 jni 实现,想必肯定会比 java 快,担心如果比 rs 实现快很多,也没必要写出来了。根据测试效果,明显比 java 实现快很多,处理同样的图片,用了7秒多,比 java 快了十倍左右。从效果图上来看,其边缘更加清晰,尖锐三角形也很多,风格与 java 实现的稍有不同,不过这些应该是因为使用不同的三角化算法导致,对耗时影响应该不大。


rs process(微信大小限制,图片压缩了)


rs cost time

最后是使用 RenderScript 实现的,为了方便描述实现过程 Demo 分步骤展示了主要的过程。处理同样的图片,通过计时器可以看到,总耗时大概在 2s以内,效率应该说还是比较能够让人接受的。正如前文提到的,使用了前文同学的 Delaunay 算法和 canvas 部分代码,所以风格应该差不多。不同的是,用 rs 处理了灰度、边缘化和采样的过程,大大节省了时间。

实现原理

根据知乎那个答案,这种效果主要有那么几个步骤:

 1. 首先将原图转为灰度图(不是必须);

 2. 使用灰度图(或原图)查找边缘,获得边缘线图;

 3. 从边缘线上采样,采样率决定后期三角的数量与图片精度;

 4. 使用上步骤得到的采样点列,生成三角化序列;

5. 遍历三角形,使用原图得到的色值填充三角形。

其中,在边缘检测上一般采用 Sobel 算法,即通过 sobel 算子计算某一点的梯度,可以简单理解为某一点与周围点灰度差异度;然后,在三角化处理上,一般采用 Delaunay 算法。

在实现方面,首先 jni 并不是一定会比 java 快的,使用 jni 一般是为了某些特定场景,其中图形处理所需要的大量数学运算就是其一,在 LowPoly 的代码中:

LowPoly.java


可见,除了取色、上色两个步骤,其他步骤都通过调用 native 的 getTriangles 方法处理,其中应该就是负责图形处理的大量运算。

对于 RenderScript,Google 这样描述:

RenderScript

https://developer.android.com/guide/topics/renderscript/compute.html

RenderScript is a framework for running computationally intensive tasks at high performance on Android. RenderScript is primarily oriented for use with data-parallel computation, although serial workloads can benefit as well. The RenderScript runtime parallelizes work across processors available on a device, such as multi-core CPUs and GPUs. This allows you to focus on expressing algorithms rather than scheduling work. RenderScript is especially useful for applications performing image processing, computational photography, or computer vision.

介绍了 RenderScript 主要基于多核 CPU 或者 GPU,主要是为了处理图形运算。早些时候,在手机处理器和图形处理器的性能普遍不高的情况下, rs 似乎并不太引人注意,从网络上少得可怜的资料就可以看出。不过,时至今日,各大手机厂商在硬件的堆砌上似乎一点也没有节制,以及 VR、 AR 等视觉技术的兴起,相信 rs 技术会有更多应用场景。

示例

Github-LowPoly

https://github.com/ReikyZ/LowPoly

基础
配置

app.gradle


RenderScript  在 Android 3.0(API 11)时首次被引入,包名为 android.renderscript;之后又添加了 Support Library android.support.v8.renderscript,最低可以兼容 Android 2.3 (API 9),SDK Tools Version 须要 22.2 及以上, Build Tools Version 须要 18.1 及以上。在应用的 .gradle 配置中需要加上蓝色的两行,以配置支持库。支持库与早先版本的 api 由较大的不同,所以下文都是以使用 Support Library 为基础。

文件目录

在 Android Studio 的 Project 视图中,在 main 目录下创建 rs 目录,用来存放 rs 脚本,在编写好脚本,经过编译后,会在 build  文件目录下分别生成  .bc 格式与 .java  文件,其中 .java 文件就是 .java 让我们可以对 rs 脚本进行反射调用。

语言

RenderScript 以 C99 作为开发语言,不支持调用 NDK 或 C 标准库的 API,但是提供了能够基本满足开发需要的 RenderScript API,包涵了丰富的基本数据类型,例如向量,矩阵,各种数学函数,具体可以参考官方文档。

使用流程

编写脚本

grayed.rs


pragma.rsh

#pragma version(1)
#pragma rs java_package_name(com.reikyz.renderscript)

对于 grayed.rs  这个脚本,首先需要添加两行包信息,这两行信息放在了 pragme.rsh 文件中引入,在有较多的脚本时,也可以把一些自定义的结构体或者函数,通过这样的方式引入,方便管理与复用。

在添加了包信息之后,我们就可以使用 rs 提供的一系列数据类型和函数,grayed.rs 这个脚本的效果是将一个图像灰度化。

调用

MainActivity.java


在编译后,我们就可以通过自动生成的 ScriptC_grayed.java  反射类对 rs 进行初始化和调用。

在 createRS 方法中,首先,获得一个 RenderScript 对象;

根据 bitmap 构建输入、输出的 Allocation 对象,对应 rs 脚本中的两个rs_allocation 对象,这两个对象的尺寸必须相同;

初始化 Grayed 脚本,至此都是一些准备工作;

调用 scriptGrayed.forEach_root(mInAllocation, mOutAllocation) 将分配的 allocation 传入, rs 执行 root 方法;

最后将生成的 输出 allocation 中的图像写入 bitmap 。

在 log 中可以注意到,在调用时 scriptGrayed.forEach_root 这个函数应该早于 “===Script root end===”这行 log 信息,实际却不是这样,因此,可以看出 rs 脚本的 root 方法并不在主线程中。

另外,java 中调用脚本的方式 scriptGrayed.forEach_root,为什么是 each_root 呢?

因为,root 还有一个重载方法 root(const uchar4 *v_in, uchar4 *v_out, uint32_t x, uint32_t y)

grayed.rs


在 grayed.rs 脚本中重载这个方法,需注意的是一个脚本只能重载一个 root 方法,否则编译时就会报错。

MainActivity.java


由于,重载包含坐标的 root 方法对 rs 脚本中的输入、输出 rs_allocation 进行操作,如果在 java 层不进行 set 操作的话,程序运行后会直接崩溃,且不会输出崩溃原因,所以编写 rs 脚本时,须要格外注意代码逻辑。


如图所示,重载的 root 方法很简单地实现了一个马赛克的图像效果。

更多

每天学习累了,看些搞笑的段子放松一下吧。关注最具娱乐精神的公众号,每天都有好心情。

如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号:

这篇关于Android RenderScript实现LowPoly效果的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/813965

相关文章

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

MySQL8.0设置redo缓存大小的实现

《MySQL8.0设置redo缓存大小的实现》本文主要在MySQL8.0.30及之后版本中使用innodb_redo_log_capacity参数在线更改redo缓存文件大小,下面就来介绍一下,具有一... mysql 8.0.30及之后版本可以使用innodb_redo_log_capacity参数来更改

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque