0

I managed to write a Kernel that transforms an input-Bitmap to a float[] of Sobel gradients (two separate Kernels for SobelX and SobelY). I did this by assigning the input-Bitmap as a global variable and then passing the Kernel based on the Output allocation and referencing the neighbors of the Input-Bitmap via rsGetElementAt. Since I actually want to calculate the Magnitude (hypot(Sx,Sy) AND the Direction (atan2(Sy,Sx)) it would be nice to do the whole thing in one Kernel-pass. If I only had to calculate the Magnitude Array, this could be done with the same structure (1 intput Bitmap, 1 Output float[]). Now I wonder, whether it is possible to just add an additional Allocation for the Direction Output (also a float[]). I tried this with the rs-function rsSetElementAt() as follows:

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

 rs_allocation gIn, direction;
 int32_t width;
 int32_t height;


 // Sobel, Magnitude und Direction
 float __attribute__((kernel)) sobel_XY(uint32_t x, uint32_t y) {
 float outX=0, outY=0;

if (x>0 && y>0 && x<(width-1) && y<(height-1)){

    uchar4 c11=rsGetElementAt_uchar4(gIn, x-1, y-1); uchar4 c12=rsGetElementAt_uchar4(gIn, x-1, y);uchar4 c13=rsGetElementAt_uchar4(gIn, x-1, y+1);
    uchar4 c21=rsGetElementAt_uchar4(gIn, x, y-1);uchar4 c23=rsGetElementAt_uchar4(gIn, x, y+1);
    uchar4 c31=rsGetElementAt_uchar4(gIn, x+1, y-1);uchar4 c32=rsGetElementAt_uchar4(gIn, x+1, y);uchar4 c33=rsGetElementAt_uchar4(gIn, x+1, y+1);

    float4 f11=rsUnpackColor8888(c11);float4 f12=rsUnpackColor8888(c12);float4 f13=rsUnpackColor8888(c13);
    float4 f21=rsUnpackColor8888(c21); float4 f23=rsUnpackColor8888(c23);
    float4 f31=rsUnpackColor8888(c31);float4 f32=rsUnpackColor8888(c32);float4 f33=rsUnpackColor8888(c33);

    outX= f11.r-f31.r + 2*(f12.r-f32.r) + f13.r-f33.r;
    outY= f11.r-f13.r + 2*(f21.r-f23.r) + f31.r-f33.r;

    float d = atan2(outY, outX);
    rsSetElementAt_float(direction, d, x, y);
    return hypot(outX, outY);

    }
}

And the corresponding Java code:

 ScriptC_sobel script;
 script=new ScriptC_sobel(rs);
 script.set_gIn(Allocation.createFromBitmap(rs, bmpGray));

 Type.Builder TypeOut = new Type.Builder(rs, Element.F32(rs));
 TypeOut.setX(width).setY(height);
 Allocation outAllocation = Allocation.createTyped(rs, TypeOut.create());

 // the following 3 lines shall reflect the allocation to the Direction output
 Type.Builder TypeDir = new Type.Builder(rs, Element.F32(rs));
 TypeDir.setX(width).setY(height);
 Allocation dirAllocation = Allocation.createTyped(rs, TypeDir.create());

 script.forEach_sobel_XY(outAllocation);
 outAllocation.copyTo(gm) ;
 dirAllocation.copyTo(gd);

Unfortunately this does not work. I am not sure, whether the problem is with the structural logic of the rs-kernel or is it because I cannot use a second Type.Builder assignment within the Java code (because the kernel is already tied to the Magnitude Output-allocation). Any help is highly appreciated. PS: I see that there is no link between the second Type.Builder assignment and the "direction" allocaton in rs - but how can this be achieved?

Settembrini
  • 1,366
  • 3
  • 20
  • 32
  • Why are you unpacking and computing on float4? These calculations will be fine with int4. Just convert to float4 right before calling atan2() and hypot(). – Miloslaw Smyk Aug 09 '15 at 02:18
  • The definition of rsunpackColor8888 is: "Unpacks a uchar4 color to float4. The resulting floats will be between 0.0 and 1.0 inclusive." Because of the latter I would need to multiply first with 255, but for some reason it does no allow conversion to int4 or uint4, i.e. uint4 f11=convert_uint4(255*rsUnpackColor8888(c11)); and int4 f11=convert_int4(255*rsUnpackColor8888(c11)); both create an error: ScriptC sym lookup failed for convert_float – Settembrini Aug 09 '15 at 15:17
  • sorry, the conversion from uchar4 to uint4 works, but the error comes with the conversion of (f11.r-f13.r +...) to float (where f11,f13 are the uint4's). – Settembrini Aug 09 '15 at 15:37

1 Answers1

1

The outAllocation is passed as a parameter to the kernel. But the existence and location of dirAllocation also has to be communicated to the Renderscript side. Do this just before starting the script:

script.set_direction(dirAllocation);

Also, read about memory allocation in Renderscript.

Miloslaw Smyk
  • 1,305
  • 10
  • 15
  • The strange thing is that this Kernel works well for my older Galaxy Tab2 (Android 4.2) but it crashes on my Galaxs S5 (Android 5.0). In the latter case the kernel is passed, but it crashes when copying the Allocation (to gm and gd). The error message ist: Fatal signal 7 (SIGBUS), code 2, fault addr 0x9e6d4000 in tid 6385. Any idea what the problem could be? I wonder because virtually the same copyTo() statements worked well when I used the individual SobelX/SobelY kernels yesterday. – Settembrini Aug 09 '15 at 12:59
  • Hard to say without seeing more of your code, but for starters check if gm and gd arrays are of a right size. – Miloslaw Smyk Aug 09 '15 at 15:47
  • I will bring the code in a new question, since this might be of interest for others too. – Settembrini Aug 09 '15 at 20:22