我试图优化我的图像处理代码,因为对于大型图像,使用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)
所以,
如何初始化allocOut,我需要一个可以复制到boolean [] []的分配。
我可以立即将allocOut复制到我的boolean [] [] truthMap,还是需要使用某种回调?我已经读过RenderScript是异步的,这会导致问题吗?
处理是在后台通过IntentService完成的,所以等待RenderScript不会成为问题。
另一种选择是让Renderscript只返回计算出的亮度值,我可以在Java代码中进行比较。可能会慢一点,但如果这是唯一有效的方法,我可以忍受。但我仍然完全迷失了如何做这样的事情。有很多关于如何让inAlloc和outAlloc都是相同维度的位图的教程,但不是我能找到的关于不同输出分配的任何东西。
感谢您的帮助!
答案 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而不是假/真。