0

I want to implement a Sobel filter in RenderScript with uchar4 as Input allocation and float[] as Output allocation. I am not quite sure whether it is possible to use different types for Input and Output allocations in a RenderScript. I want to develop the solution myself, but would be grateful to get some advice on the best Renderscript structure to takle that Problem. Somewhere I read, that it is possible to use

float attribute((kernel)) root(uchar4 *v_in, uint32_t x, uint32_t y) { }

Would you recommend such Approach or can this be done without using actually a kernel, i.e. just a function? Thanks in advance.

My rs code for the Sobel (X direction) now looks as follows:

#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;
}

What I am struggling is passing the Parameters from Java side:

        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[][].

Settembrini
  • 1,366
  • 3
  • 20
  • 32

1 Answers1

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);
Miloslaw Smyk
  • 1,305
  • 10
  • 15
  • Once more: thanks a lot Miloslaw, so glad to have your help. This link is what I was looking for, it contains all elements I need . My plan is as follows: Calc SobelX and SobelY in two separate Kernels (therefore float) and then use them to calculate Magnitude AND Direction - possibly in further Kernels. Background is that I want to implement a proprietary Canny implementation (own methods for auto-threshold and hysteresis) as a basis for further processing - all the further steps are then done on bool-arrays. I don't need "hyper" speed, but somewhat more would be helpful. – Settembrini Aug 07 '15 at 22:00
  • It works! Just had to complete the Input allocation with script.set_gIn(Allocation.createFromBitmap(rs, bmpGray)); What a fantastic thing RenderScript is! It's so fast. Now I believe in RenderScript! Just great. Thank you again, Miloslaw. – Settembrini Aug 08 '15 at 13:53
  • Just as a note to anyone doing the same: the kernel pass is 1.) for y and 2.) for x, which is important for the order of values in the output float[]. Also note that in the above code I confused SobelX with SobelY. – Settembrini Aug 08 '15 at 14:08
  • second note: using rsUnpackColor8888() is even faster than the above convert_float4(), particularly on my older Galaxy Tab 2. – Settembrini Aug 08 '15 at 14:34