android - 如何为 RenderScript 输出分配 bool 数组?

标签 android c renderscript

我正在尝试优化我的图像处理代码,因为对于大型图像,使用 Java 处理需要很长时间。

我用 DDMS 做了一些方法分析,发现这个方法占用了将近 50% 的 cpu 时间:

private int getBrightness(int color) {
    // returns an int from 0-255 where zero is pure black and 255 is pure white,
    // weighted to correspond to perceived brightness
    // http://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx
    int red = Color.red(color);
    int blue = Color.blue(color);
    int green = Color.green(color);
    int brightness = (int) Math.round(Math.sqrt((0.241 * red * red) + (0.691 * green * green) + (0.068 * blue * blue)));
    return brightness;
}

具体来说,对 Math.sqrt() 和 Math.round() 的调用才是真正的罪魁祸首。再加上这是串行计算的事实,而它可以并行完成,这意味着我的处理时间太长了。

有人向我指出了 RenderScript。我认为这听起来很适合我正在尝试做的事情。我懂 C++ 但不懂 C,而且我很难完成我想要完成的事情。

基本上,在处理时我不需要知道每个像素的实际亮度,只需要知道它是高于还是低于阈值(在该对象的生命周期内不会改变)。所以我可以简单地创建一个 bool 值数组,告诉我像素是 >= 阈值 (true) 还是 < 阈值 (false)。所以我可以将亮度计算移至渲染脚本中的 C 代码。

我想直接将真值或假值返回到输出分配中。这就是我遇到的问题。

这是我的 Renderscript C 代码:

#pragma version(1)
#pragma rs java_package_name(com.mushroomhouse.pixelbomb)
#pragma rs_fp_relaxed

int threshold = 160;

bool __attribute__((kernel)) generate(uchar4 in) {
    int r = (int) (255*sqrt((float)((0.241 * in.r * in.r) + (0.691 * in.g * in.g) + (0.068 * in.b * in.b))));
    return (r>threshold);
}

这是我的处理类中的相关代码:

(Member variables)
...
RenderScript myRS;
ScriptC_brightness_map script;
Allocation allocIn, allocOut;
boolean[][] truthMap;

(Public Constructor) {
    ...
    myRS = RenderScript.create(context);
    script = new ScriptC_brightness_map(myRS);    
}

(Initialization before processing is done)
...
truthMap = new boolean[width][height];
allocIn = Allocation.createFromBitmap(myRS, product);
allocOut = ????
script.set_threshold(brightnessValue);
script.forEach_generate(allocIn, allocOut);
...

(Processing)

所以,

  1. 我如何初始化 allocOut,我需要一个可以复制到 boolean[][] 的分配。

  2. 我可以立即将 allocOut 复制到我的 boolean[][] truthMap 还是我需要使用某种回调?我读到 RenderScript 是异步的,这会导致问题吗?

处理是通过后台的 IntentService 完成的,因此等待 RenderScript 不会有问题。

另一种选择是让 Renderscript 简单地返回计算出的亮度值,我可以在 Java 代码中进行比较。可能会慢一点,但如果这是唯一可行的方法,我可以接受。但是我仍然完全不知道如何做这样的事情。关于如何使 inAlloc 和 outAlloc 成为相同尺寸的位图的教程很多,但我找不到关于不同输出分配的任何内容。

感谢您的帮助!

最佳答案

一些事情。

首先,请记住,根据 C99 规范,当您在没有限定符(例如 0.53 或类似的东西)的函数中使用浮点常量时,它们在技术上是 double 的。换句话说,它们。除非你知道你需要 double ,否则你可能不需要它,对于像这样的简单图像处理,你绝对不需要它。只需将 f 添加到常量(例如 0.53f),它将作为单精度值处理。

您确实需要 allocOut 的分配。最简单的方法是使用 Type.Builder。使用与位图尺寸相同的 Element.BOOLEAN 构建二维类型。要将其复制回来,您需要复制到 boolean[],而不是 boolean[][],并使用 truthMap[y * width] 对其进行索引+ x]。 IIRC,您可以使用 copyTo 将数据获取到 boolean[] 中,只要它的大小是分配的宽度 * 高度。

如果你不能复制(老实说我忘记了,我已经很长时间没有处理 Java bool 值了),你可以切换到 byte[] 和 Element.U8 作为RS 元素并写入 0 或 1 而不是 false/true。

关于android - 如何为 RenderScript 输出分配 bool 数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25816261/

相关文章:

c - 打开: 'sh: permission denied"

c - 新 child 的 xml 缩进和换行符

c - 套接字编程中的霍夫曼编码

android - 为什么那些 Google 图像处理示例 Renderscript 在 Nexus 5 的 GPU 上运行速度较慢

Android API 与 renderscript.type 类不一致

android - Android 上带有 RenderScript 的 RSInvalidStateException

java - 安卓服务 START_STICKY START_NOT_STICKY

android - Android-确定位图上具有不同分辨率的特定位置(X,Y坐标)?

android - 中断 HttpURLConnection 请求 Android

android - 如何让用户始终保持登录状态 "Connected with Server"