如何为RenderScript输出分配布尔数组?

时间:2014-09-12 20:22:27

标签: 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,而且我很难完成我想要完成的任务。

基本上,在处理时,我不需要知道每个像素的实际亮度,只需要知道它是高于还是低于阈值(在该对象的生命周期内不会发生变化)。所以我可以简单地创建一个布尔值数组,告诉我像素是否是> =阈值(真)或<门槛(假)。所以我可以将亮度计算移动到renderscript中的C代码。

我想在输出分配中直接返回true或false值。这就是我遇到的麻烦。

这是我的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是异步的,这会导致问题吗?

  3. 处理是在后台通过IntentService完成的,所以等待RenderScript不会成为问题。

    另一种选择是让Renderscript只返回计算出的亮度值,我可以在Java代码中进行比较。可能会慢一点,但如果这是唯一有效的方法,我可以忍受。但我仍然完全迷失了如何做这样的事情。有很多关于如何让inAlloc和outAlloc都是相同维度的位图的教程,但不是我能找到的关于不同输出分配的任何东西。

    感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

夫妻俩。

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

您确实需要allocOut的分配。最简单的方法是使用Type.Builder。使用与您的位图具有相同尺寸的Element.BOOLEAN构建2D类型。要将其复制回来,您希望复制到boolean[],而不是boolean[][],并使用truthMap[y * width + x]复制到copyTo。 IIRC,您可以使用boolean[]将数据导入Element.U8,只要其大小为分配的宽度*高度。

如果你不能复制(我老实说忘了,我很长时间没有处理过Java布尔),你可以切换到一个byte []和{{1}}作为RS元素并写0或1而不是假/真。