get average value of red channel from bitmap using Renderscript android

陌路散爱 提交于 2021-02-08 10:12:24

问题


I'm currently working in an android application where i need to compute the average value of red channel in a bitmap and i just discovered Renderscript that has a fast way to access bitmap pixels. However until now i modified google developer page's code and failed to do want i wanted and here is my code:

Sript:

int *sum;

uchar4 __attribute__ ((kernel)) invert(uchar4 in, uint32_t x, uint32_t y){
uchar4 out = in;
sum[0] += in.r;
out.r = 255 - in.r; 
out.g = 255 - in.g;
out.b = 255 - in.b;
return out;
}

so what i try to do above is sum up all red value in the pointer "sum" and in java code:

int [] sum = new int[2];
Allocation data = Allocation.createSized(rs, Elelement.I32(rs), sum.length, Allocation.USAGE_SCRIPT);
data.copy1DRangeFrom(0, sum.length, sum);

Bitmap output = Bitmap.createBitmap(input.getWith(), input.getHeight(), input.getConfig);
Allocation in = Allocation.createFromBitmap(rs, input);
Allocation out = Allocation.createFromBitmap(rs, output);

ScriptC_root root = new ScriptC_root(rs);
root.bind_sum(sum);
root.forEach_invert(in, out);
out.copyTo(output);
data.copyTo(sum); //Here is where i am trying to geck the sum

//so i try to compute the average 
float avg = sum[0] / input.getWidth() * input.getHeight();

For the bitmap invert operation i am getting exactly the expected result
The value i get at avg is too small(under 150) while the input bitmap is a completely red image.
I tried simply to increment the pointer *sum in the script to check if the foEach loop is accessing exactly the same number of pixels every time and in every run i get different number.
A help about how to do this properly would be the most welcome.


回答1:


Note: this code is strictly related to the main question, how to get the average of a channel.

What you want to achieve can be done in this way:

1) RenderScript

#pragma rs java_package_name(net.hydex11.channelaverageexample)
#pragma rs_fp_relaxed
#pragma version(1)

// Use two global counters
static int totalSum = 0;
static int counter = 0;

// One kernel just sums up the channel red value and increments 
// the global counter by 1 for each pixel
void __attribute__((kernel)) addRedChannel(uchar4 in){

 rsAtomicAdd(&totalSum, in.r);
 rsAtomicInc(&counter);

}

// This kernel places, inside the output allocation, the average
int __attribute__((kernel)) getTotalSum(int x){
    return totalSum/counter;
}

void resetCounters(){

    totalSum = 0;
    counter = 0;

}

Note: I used the rsAtomic* functions because, if you are working on a global variable from different threads, you have to use thread-safe operations (e.g. Thread safety).

2) Java side

private void example() {

    RenderScript mRS = RenderScript.create(this);

    // Loads example image
    Bitmap inputImage = BitmapFactory.decodeResource(getResources(), R.drawable.houseimage);
    Allocation inputAllocation = Allocation.createFromBitmap(mRS, inputImage);

    // Allocation where to store the sum result (for output purposes)
    Allocation sumAllocation = Allocation.createSized(mRS, Element.I32(mRS), 1);

    // Init script
    ScriptC_average scriptC_average = new ScriptC_average(mRS);

    // If you have a cycle, you have to reset the counters on each cycle
    //scriptC_average.invoke_resetCounters();

    // 1. Execute sum kernel
    scriptC_average.forEach_addRedChannel(inputAllocation);

    // 2. Execute a kernel that copies the sum into an output allocation
    scriptC_average.forEach_getTotalSum(sumAllocation);

    int sumArray[] = new int[1];
    sumAllocation.copyTo(sumArray);

    // E.g. simple output can be 66
    Log.d("AverageExample", String.format("The average of red channel is %d", sumArray[0]));

}

Reference: RenderScript: parallel computing on Android, the easy way



来源:https://stackoverflow.com/questions/38908491/get-average-value-of-red-channel-from-bitmap-using-renderscript-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!