使用 Renderscript 从位图中获取红色通道的平均值 android
get average value of red channel from bitmap using Renderscript android
我目前在一个 android 应用程序中工作,我需要计算位图中红色通道的平均值,我刚刚发现 Renderscript 可以快速访问位图像素。
但是直到现在我修改了 google 开发者页面的代码,但未能如愿,这是我的代码:
脚本:
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;
}
所以我在上面尝试做的是总结指针 "sum" 和 java 代码中的所有红色值:
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();
对于位图反转操作,我得到了预期的结果
我在 avg 得到的值太小(低于 150),而输入位图是一个完全红色的图像。
我尝试简单地增加脚本中的指针 *sum 以检查 foEach 循环是否每次都访问完全相同数量的像素,并且在每个 运行 中我得到不同的数字。
欢迎提供有关如何正确执行此操作的帮助。
注意:此代码与主要问题密切相关,如何获取通道的平均值。
你想达到的效果可以这样实现:
1) 渲染脚本
#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;
}
注意: 我使用了 rsAtomic*
函数,因为,如果您正在处理来自不同线程的全局变量,则必须使用线程安全操作(例如Thread safety)。
2) Java 边
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]));
}
参考:RenderScript: parallel computing on Android, the easy way
我目前在一个 android 应用程序中工作,我需要计算位图中红色通道的平均值,我刚刚发现 Renderscript 可以快速访问位图像素。
但是直到现在我修改了 google 开发者页面的代码,但未能如愿,这是我的代码:
脚本:
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;
}
所以我在上面尝试做的是总结指针 "sum" 和 java 代码中的所有红色值:
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();
对于位图反转操作,我得到了预期的结果
我在 avg 得到的值太小(低于 150),而输入位图是一个完全红色的图像。
我尝试简单地增加脚本中的指针 *sum 以检查 foEach 循环是否每次都访问完全相同数量的像素,并且在每个 运行 中我得到不同的数字。
欢迎提供有关如何正确执行此操作的帮助。
注意:此代码与主要问题密切相关,如何获取通道的平均值。
你想达到的效果可以这样实现:
1) 渲染脚本
#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;
}
注意: 我使用了 rsAtomic*
函数,因为,如果您正在处理来自不同线程的全局变量,则必须使用线程安全操作(例如Thread safety)。
2) Java 边
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]));
}
参考:RenderScript: parallel computing on Android, the easy way