0

我想在 RenderScript 中实现一个 Sobel 过滤器,其中 uchar4 作为输入分配,float[] 作为输出分配。我不太确定是否可以在 RenderScript 中为输入和输出分配使用不同的类型。我想自己开发解决方案,但如果能获得一些关于解决该问题的最佳 Renderscript 结构的建议,我将不胜感激。我在某处读到,可以使用

浮动属性((内核))根(uchar4 *v_in,uint32_t x,uint32_t y){}

你会推荐这样的方法还是可以在不使用实际内核的情况下完成,即只是一个函数?提前致谢。

我的 Sobel(X 方向)的 rs 代码现在如下所示:

#pragma version(1)
#pragma rs java_package_name(com.example.xxx)
#pragma rs_fp_relaxed

rs_allocation gIn;
int32_t width;
int32_t height;

float __attribute__((kernel)) sobelX(uchar4 *v_in, uint32_t x, uint32_t y)    {
float out=0;

 if (x>0 && y>0 && x<(width-1) && y<(height-1){
uchar4 c11=rsGetElementAt_uchar4(gIn, x-1, y-1);
uchar4 c21=rsGetElementAt_uchar4(gIn, x, y-1);
uchar4 c31=rsGetElementAt_uchar4(gIn, x+1, y-1);
uchar4 c13=rsGetElementAt_uchar4(gIn, x-1, y+1);
uchar4 c23=rsGetElementAt_uchar4(gIn, x, y+1);
uchar4 c33=rsGetElementAt_uchar4(gIn, x+1, y+1);

float4 f11=convert_float4(c11);
float4 f21=convert_float4(c21);
float4 f31=convert_float4(c31);
float4 f13=convert_float4(c13);
float4 f23=convert_float4(c23);
float4 f33=convert_float4(c33);

out= f11.r-f13.r + 2*(f21.r-f23.r) + f31.r-f33.r;
}

return out;
}

我正在努力从Java端传递参数:

        float[][] gx = new float[width][height];
        ScriptC_sobel script;
        script=new ScriptC_sobel(rs);

        script.set_width(width) ;
        script.set_height(height) ;
        script.set_gIn(bmpGray);

        Allocation inAllocation = Allocation.createFromBitmap(rs, bmpGray, Allocation.MipmapControl.MIPMAP_NONE,
                Allocation.USAGE_SCRIPT);
        Allocation outAllocation = Allocation.createTyped(rs, float,2) ;

        script.forEach_sobelX(inAllocation, outAllocation);
        outAllocation.copyTo(gx) ;

I understand that, in order to use rsGetElementAt function (to access neighboring data within the kernel) I need to set the input allocation as a script global as well (rs_allocation gIn in rs code). However, I'm not sure how to handle this "double allocation" from the Java side. Also the outAllocation Statement in the Java code is probably not correct. Specifiyally I am not sure, whether the Kernel will returned this as float[] or as float[][].

4

1 回答 1

1

It is possible to use different types for input and output. In your case, I would actually suggest:

float __attribute__((kernel)) sobel(unchar4 *v_in, uint32_t x, uint32_t y) {}

You certainly want to use a kernel, so that the performance can benefit from execution by multiple threads.

Also, have a look at this example of doing 3x3 convolution in RS.

UPDATE: generally, the best in/out parameters to use depend on the type of output you want this filter to generate - is it just the magnitude? Then uint output will most likely suffice.

UPDATE2: If you are going to use a variable to pass input allocation, then you don't need it in the kernel parameters, i.e.:

float __attribute__((kernel)) sobelX(uint32_t x, uint32_t y)

The rest of the script looks ok (sans missing parenthesis in the conditional). As for the Java part, below I am pasting a demonstration of how you should prepare the output allocation and start the script. The kernel will then be invoked for every cell (i.e. every float) in the output allocation.

            float[] gx = new float[width * height];
            Type.Builder TypeIn = new Type.Builder(mRS, Element.F32(mRS));
            TypeIn.setX(width).setY(height);

            Allocation outAllocation = Allocation.createTyped(mRS, TypeIn.create());

            mScript.forEach_sobelX(outAllocation);
于 2015-08-07T21:02:50.547 回答