Android 上带有 RenderScript 的中值滤波器
Median filter with RenderScript on Android
我正在迈出使用 RenderScript 进行图像处理的第一步。
现在我正在尝试用它为 Android 实现一个中值过滤器。
基本上我尝试用它做的是:
它获取位图格式的图像,为每个像素及其 8 个相邻像素(没有边缘情况)运行 3x3 过滤器,计算每个颜色通道的中值并相应地设置输出像素。
我试过它是否适用于像这样的简单反转渲染脚本:
uchar4 RS_KERNEL invert(uchar4 in, uint32_t x, uint32_t y) {
uchar4 out = in;
out.r = 255 - in.r;
out.g = 255 - in.g;
out.b = 255 - in.b;
return out;
}
而且效果很好。
但是,当我更改 RenderScript 来计算中位数时,我得到的只是黑色图片输出。
这是 RenderScript 代码:
#pragma version(1)
#pragma rs_fp_relaxed
#pragma rs java_package_name(com.google.android.GoogleCamera)
#include "rs_debug.rsh"
rs_allocation input;
uint32_t width;
uint32_t height;
static uchar medi(uchar colors[]) {
//sorting just to half
for(int i = 0; i < 5; i++){
int minIndex = i;
uchar minValue = colors[i];
//loop until end
for(int j = i+1; j < 9; j++){
if (colors[j] < minValue) {
minIndex = j;
minValue = colors[j];
//swap
colors[j] = colors[i];
colors[i] = minValue;
}
}
}
return colors[4];
}
uchar4 __attribute__((kernel)) median(uchar4 in, uint32_t x, uint32_t y) {
uchar4 out = in;
//edge
if (x == 0 || x == width || y == 0 || y == height)
return out;
//all surronding pixels (TopLeft .. BottomRight)
uchar4 tl = rsGetElementAt_uchar4(input, x-1, y+1);
uchar4 tm = rsGetElementAt_uchar4(input, x, y+1);
uchar4 tr = rsGetElementAt_uchar4(input, x+1, y+1);
uchar4 l = rsGetElementAt_uchar4(input, x-1, y);
uchar4 r = rsGetElementAt_uchar4(input, x+1, y);
uchar4 bl = rsGetElementAt_uchar4(input, x-1, y-1);
uchar4 bm = rsGetElementAt_uchar4(input, x, y-1);
uchar4 br = rsGetElementAt_uchar4(input, x+1, y-1);
//array for each color channel
uchar reds[] = {tl.r, tm.r, tr.r, l.r, r.r, bl.r, bm.r, br.r, in.r};
uchar greens[] = {tl.g, tm.g, tr.g, l.g, r.g, bl.g, bm.g, br.g, in.g};
uchar blues[] = {tl.b, tm.b, tr.b, l.b, r.b, bl.b, bm.b, br.b, in.b};
uchar alphas[] = {tl.a, tm.a, tr.a, l.a, r.a, bl.a, bm.a, br.a, in.a};
//get median values
out.r = medi(reds);
out.g = medi(greens);
out.b = medi(blues);
out.a = medi(alphas);
return out;
}
以防调用 java 部分:
private static Runnable runMedian(final Bitmap original, final File file) {
return new Runnable() {
@Override
public void run() {
//Create new bitmap
Bitmap bitmap = original.copy(original.getConfig(), true);
//Create renderscript
RenderScript rs = RenderScript.create(CameraActivity.staticContext);
//Create allocation from Bitmap
Allocation allocationA = Allocation.createFromBitmap(rs, bitmap);
//Create allocation with same type
Allocation allocationB = Allocation.createTyped(rs, allocationA.getType());
//Create script from rs file
ScriptC_median medianScript = new ScriptC_median(rs);
medianScript.set_input(allocationA);
medianScript.set_width(original.getWidth());
medianScript.set_height(original.getWidth());
medianScript.forEach_median(allocationA, allocationB);
//Copy script result into bitmap
allocationB.copyTo(bitmap);
//Destroy everything to free memory
allocationA.destroy();
allocationB.destroy();
medianScript.destroy();
rs.destroy();
//write resulting bitmap to file
writeFile(file, bitmap, "median");
}
};
}
希望知道的人能帮帮我。
祝福
您可能需要修改对边缘的处理:索引 x 从 0 到 width-1,因此边缘位于 width-1(和 height-1)。
在 java 部分,除非宽度和高度相同,否则 medianScript.set_height(original.getWidth());
可能应该读作 original.getHeight()
。
我正在迈出使用 RenderScript 进行图像处理的第一步。 现在我正在尝试用它为 Android 实现一个中值过滤器。 基本上我尝试用它做的是: 它获取位图格式的图像,为每个像素及其 8 个相邻像素(没有边缘情况)运行 3x3 过滤器,计算每个颜色通道的中值并相应地设置输出像素。
我试过它是否适用于像这样的简单反转渲染脚本:
uchar4 RS_KERNEL invert(uchar4 in, uint32_t x, uint32_t y) {
uchar4 out = in;
out.r = 255 - in.r;
out.g = 255 - in.g;
out.b = 255 - in.b;
return out;
}
而且效果很好。 但是,当我更改 RenderScript 来计算中位数时,我得到的只是黑色图片输出。
这是 RenderScript 代码:
#pragma version(1)
#pragma rs_fp_relaxed
#pragma rs java_package_name(com.google.android.GoogleCamera)
#include "rs_debug.rsh"
rs_allocation input;
uint32_t width;
uint32_t height;
static uchar medi(uchar colors[]) {
//sorting just to half
for(int i = 0; i < 5; i++){
int minIndex = i;
uchar minValue = colors[i];
//loop until end
for(int j = i+1; j < 9; j++){
if (colors[j] < minValue) {
minIndex = j;
minValue = colors[j];
//swap
colors[j] = colors[i];
colors[i] = minValue;
}
}
}
return colors[4];
}
uchar4 __attribute__((kernel)) median(uchar4 in, uint32_t x, uint32_t y) {
uchar4 out = in;
//edge
if (x == 0 || x == width || y == 0 || y == height)
return out;
//all surronding pixels (TopLeft .. BottomRight)
uchar4 tl = rsGetElementAt_uchar4(input, x-1, y+1);
uchar4 tm = rsGetElementAt_uchar4(input, x, y+1);
uchar4 tr = rsGetElementAt_uchar4(input, x+1, y+1);
uchar4 l = rsGetElementAt_uchar4(input, x-1, y);
uchar4 r = rsGetElementAt_uchar4(input, x+1, y);
uchar4 bl = rsGetElementAt_uchar4(input, x-1, y-1);
uchar4 bm = rsGetElementAt_uchar4(input, x, y-1);
uchar4 br = rsGetElementAt_uchar4(input, x+1, y-1);
//array for each color channel
uchar reds[] = {tl.r, tm.r, tr.r, l.r, r.r, bl.r, bm.r, br.r, in.r};
uchar greens[] = {tl.g, tm.g, tr.g, l.g, r.g, bl.g, bm.g, br.g, in.g};
uchar blues[] = {tl.b, tm.b, tr.b, l.b, r.b, bl.b, bm.b, br.b, in.b};
uchar alphas[] = {tl.a, tm.a, tr.a, l.a, r.a, bl.a, bm.a, br.a, in.a};
//get median values
out.r = medi(reds);
out.g = medi(greens);
out.b = medi(blues);
out.a = medi(alphas);
return out;
}
以防调用 java 部分:
private static Runnable runMedian(final Bitmap original, final File file) {
return new Runnable() {
@Override
public void run() {
//Create new bitmap
Bitmap bitmap = original.copy(original.getConfig(), true);
//Create renderscript
RenderScript rs = RenderScript.create(CameraActivity.staticContext);
//Create allocation from Bitmap
Allocation allocationA = Allocation.createFromBitmap(rs, bitmap);
//Create allocation with same type
Allocation allocationB = Allocation.createTyped(rs, allocationA.getType());
//Create script from rs file
ScriptC_median medianScript = new ScriptC_median(rs);
medianScript.set_input(allocationA);
medianScript.set_width(original.getWidth());
medianScript.set_height(original.getWidth());
medianScript.forEach_median(allocationA, allocationB);
//Copy script result into bitmap
allocationB.copyTo(bitmap);
//Destroy everything to free memory
allocationA.destroy();
allocationB.destroy();
medianScript.destroy();
rs.destroy();
//write resulting bitmap to file
writeFile(file, bitmap, "median");
}
};
}
希望知道的人能帮帮我。 祝福
您可能需要修改对边缘的处理:索引 x 从 0 到 width-1,因此边缘位于 width-1(和 height-1)。
在 java 部分,除非宽度和高度相同,否则 medianScript.set_height(original.getWidth());
可能应该读作 original.getHeight()
。