2014-09-12 57 views
0

我想優化我的圖像處理代碼,因爲對於大圖像,使用Java進行處理需要很長時間。如何爲RenderScript輸出分配一個布爾數組?

我做了一些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,而我正在努力完成自己想要完成的任務。

基本上,在處理時,我不需要知道每個像素的實際亮度,只是它是高於還是低於閾值(在此對象的生命週期內不會改變)。因此,我可以簡單地創建一個布爾值數組,告訴我像素是否≥閾值(true)或閾值(false)。所以我可以將亮度計算移動到renderscript中的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成爲相同尺寸的位圖的教程,但並非我可以找到關於不同輸出分配的任何東西。

感謝您的幫助!

回答

2

夫婦的事情。首先,請記住,根據C99規範,當在沒有限定符的函數(例如0.53或類似的東西)中有浮點常量時,它們在技術上是雙精度的。換句話說,他們是。除非你知道你需要雙精度,否則你可能不需要它,而對於這樣的簡單圖像處理,你肯定不需要它。只需在常量(例如0.53f)中添加一個f,它將作爲單精度值處理。

您確實需要allocOut的分配。最簡單的方法是使用Type.Builder。與Element.BOOLEAN一起構建2D類型,其尺寸與您的位圖尺寸相同。要將其複製回來,您希望將其複製到boolean[]而不是boolean[][],並將其索引到truthMap[y * width + x]。 IIRC,只要其大小爲分配的寬度*高度,就可以使用copyTo將數據存入boolean[]。如果你不能複製(我老實說忘了,我很久沒有處理Java布爾),你可以切換到一個byte []和Element.U8作爲RS元素,並寫入0或1,而不是錯誤/真實。

+0

感謝關於浮筒的提示。我改變了我的方法,我非常接近它的工作。我在我的問題結尾處做了我的建議,讓RenderScript返回一個int foreach並將其複製到int [] brightnessMap中。現在我遇到了運行時錯誤:輸入和輸出參數之間的尺寸不匹配。 'allocOut = Allocation.createSized(myRS,Element.I32(myRS),brightnessMap.length);' 所以我想我必須做一個2D分配。現在看看。感謝您的見解。 – Eric 2014-09-13 00:10:05

+1

是的,輸入和輸出分配必須具有相同的尺寸(x和y),但我認爲2D分配可以複製到1D Java數組中。 – 2014-09-13 00:24:41

相關問題