B4A Class RenderScript Intrinsics Function Example

*Note there is workaround needed to avoid running your processes out of memory when using this, please see my post int his thread: http://www.b4x.com/android/forum/threads/bitmaps-subs-and-garbage-collection.37660/
*

I was searching for a higher performance method of analyzing images (real-time), and stubled on the fairly new feature of android (4.2 and later only I believe) - RenderScript Intrinsics

http://android-developers.blogspot.com/2013/08/renderscript-intrinsics.html


Performance in release mode:
Gaussian Blur (7 pixels) 640x480:
RSImageProcessingLibrary: 16 seconds
RenderScript GuassianBlur: 100 ms

I have only tested this on Android 4.2.2 on Boundary Devices nitrogen6x (imx6), it will not work on my API17 emulator (get random colored noise as output bitmap), I think it requires a hardware GPU. Requires Reflection library.

I may update this post with more Intrinsic functions and turn it into a complete class if I need them in my project (I may end up using the 3x3 and 5x5 convolutions as well for example)

B4X:
Public Sub GaussianBlur(bm As Bitmap, radius As Float) As Bitmap
    Dim Obj1 As Reflector

    Dim time As Long
    time = DateTime.Now

    Dim args(1) As Object
    Dim types(1) As String

    'RenderScript rs = RenderScript.create(getApplicationContext());
    Dim rs As Reflector
    args(0) =  Obj1.GetContext
    types(0) = "android.content.Context"
    rs.Target = Obj1.RunStaticMethod("android.renderscript.RenderScript","create", args, types)

    'Element.U8_4(rs)
    Dim oU8 As Reflector
    args(0) = rs.Target
    types(0) = "android.renderscript.RenderScript"
    oU8.Target = Obj1.RunStaticMethod("android.renderscript.Element","U8_4", args, types)

    '    ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur
    '.create(rs, Element.U8_4(rs));
    Dim theIntrinsic As Reflector
    Dim args2(2) As Object
    Dim types2(2) As String
    args2(0) =  rs.Target
    types2(0) = "android.renderscript.RenderScript"
    args2(1) =  oU8.Target
    types2(1) = "android.renderscript.Element"
    theIntrinsic.Target = Obj1.RunStaticMethod("android.renderscript.ScriptIntrinsicBlur","create", args2, types2)

    'Allocation tmpIn = Allocation.createFromBitmap(rs, bm);
    'Dim bm As Bitmap
    'bm = LoadBitmap(File.DirAssets, "reusedefault.bmp")
    Dim tmpIn As Reflector
    args2(0) =  rs.Target
    types2(0) = "android.renderscript.RenderScript"
    args2(1) =  bm
    types2(1) = "android.graphics.Bitmap"
    tmpIn.Target = Obj1.RunStaticMethod("android.renderscript.Allocation", "createFromBitmap", args2, types2)

    'Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
    Dim outputBitmap As Bitmap
    outputBitmap.InitializeMutable(bm.Width,bm.Height)
    Dim tmpOut As Reflector
    args2(0) =  rs.Target
    types2(0) = "android.renderscript.RenderScript"
    args2(1) =  outputBitmap
    types2(1) = "android.graphics.Bitmap"
    tmpOut.Target = Obj1.RunStaticMethod("android.renderscript.Allocation", "createFromBitmap", args2, types2)

    'theIntrinsic.setRadius(25.f);
    args(0) =  radius
    types(0) = "java.lang.float"
    theIntrinsic.RunPublicmethod("setRadius",args,types)

    'theIntrinsic.setInput(tmpIn);
    args(0) =  tmpIn.Target
    types(0) = "android.renderscript.Allocation"
    theIntrinsic.RunPublicmethod("setInput",args,types)

    'theIntrinsic.forEach(tmpOut);
    args(0) =  tmpOut.Target
    types(0) = "android.renderscript.Allocation"
    theIntrinsic.RunPublicmethod("forEach",args,types)

    'tmpOut.copyTo(outputBitmap);
    args(0) =  outputBitmap
    types(0) = "android.graphics.Bitmap"
    tmpOut.RunMethod4("copyTo",args, types)

    Log("Blur took: " & (DateTime.Now - time) & " ms")

    Return outputBitmap

End Sub

Here is code to do a 5x5 convolution:

B4X:
Public Sub Convolution5x5(bm As Bitmap, coeff() As  Float) As Bitmap

    Dim Obj1 As Reflector
    Dim time As Long
    time = DateTime.Now
    Dim args(1) As Object
    Dim types(1) As String

    'Element.U8_4(rs)
    Dim oU8 As Reflector
    args(0) = rs.Target
    types(0) = "android.renderscript.RenderScript"
    oU8.Target = Obj1.RunStaticMethod("android.renderscript.Element","U8_4", args, types)

    Dim theIntrinsic As Reflector
    Dim args2(2) As Object
    Dim types2(2) As String
    args2(0) =  rs.Target
    types2(0) = "android.renderscript.RenderScript"
    args2(1) =  oU8.Target
    types2(1) = "android.renderscript.Element"
    theIntrinsic.Target = Obj1.RunStaticMethod("android.renderscript.ScriptIntrinsicConvolve5x5","create", args2, types2)

    'Allocation tmpIn = Allocation.createFromBitmap(rs, bm);
    'Dim bm As Bitmap
    'bm = LoadBitmap(File.DirAssets, "reusedefault.bmp")
    Dim tmpIn As Reflector
    args2(0) =  rs.Target
    types2(0) = "android.renderscript.RenderScript"
    args2(1) =  bm
    types2(1) = "android.graphics.Bitmap"
    tmpIn.Target = Obj1.RunStaticMethod("android.renderscript.Allocation", "createFromBitmap", args2, types2)

    'Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
    Dim outputBitmap As Bitmap
    outputBitmap.InitializeMutable(bm.Width,bm.Height)
    Dim tmpOut As Reflector
    args2(0) =  rs.Target
    types2(0) = "android.renderscript.RenderScript"
    args2(1) =  outputBitmap
    types2(1) = "android.graphics.Bitmap"
    tmpOut.Target = Obj1.RunStaticMethod("android.renderscript.Allocation", "createFromBitmap", args2, types2)

    'theIntrinsic.setCoefficients(float[]);
    args(0) =  coeff
    'types(0) = "java.lang.float" this needs to be passed as "[F" for array of float, not primitive type
    theIntrinsic.RunPublicmethod("setCoefficients",args,Array As String("[F"))

    args(0) =  tmpIn.Target
    types(0) = "android.renderscript.Allocation"
    theIntrinsic.RunPublicmethod("setInput",args,types)

    args(0) =  tmpOut.Target
    types(0) = "android.renderscript.Allocation"
    theIntrinsic.RunPublicmethod("forEach",args,types)

    args(0) =  outputBitmap
    types(0) = "android.graphics.Bitmap"
    tmpOut.RunMethod4("copyTo",args, types)

    Log("Convolution took: " & (DateTime.Now - time) & " ms")

    Return outputBitmap

End Sub

It is called like so:

B4X:
bitmapOut = Convolution5x5(bitmapIn,Array As Float( _
0,0,0,0,0, _
0,1,1,1,0, _
0,1,2,1,0, _
0,1,1,1,0, _
0,0,0,0,0 _
))

Where
bitmapOut bitmapIn are Bitmap

You can find more info about kernels to use to achieve filter effects @
http://en.wikipedia.org/wiki/Kernel_(image_processing)
http://docs.gimp.org/en/plug-in-convmatrix.html

From my testing 5x5 convolution takes about the same time as gaussian blur on hardware with GPU support. So a 512x512 image takes about 10 ms to process on hardware made in the past two years. It allows for emboss/sharpen/edge detect type filters. Getting fancy you can do the "oil painting" filters and such from photoshop by stacking convolutions.

In the future this would probably be easier to do with inline java rather than reflection.
 
Last edited:

urikupfer

Member
Licensed User
Longtime User
Hi drewG
Can you please add more samples with the using of RenderScript Intrinsics.
uri
 

DrewG

Member
Licensed User
Longtime User
urikupfer, I will post more when I get them done, eventually I will have to do an edge detection using the convolution Intrinsic, but its fallen off my radar as the RS image processing library has been fast enough for my other needs besides blurring.

Please be aware that there is a memory usage issue with the code above, please see the workaround in the thread below, basically you just need to make the "rs" reflector a global variable to avoid a memory leak situation (not sure why the reflector is not being garbage collected, but its not, so you need to force B4A to make only one of them!).
http://www.b4x.com/android/forum/threads/bitmaps-subs-and-garbage-collection.37660/
 

yiankos1

Well-Known Member
Licensed User
Longtime User
When i try to run convolution5x5 throws me this error. Do you know why?
B4X:
java.lang.NullPointerException: Attempt to read from field 'android.renderscript.Element android.renderscript.RenderScript.mElement_UCHAR_4' on a null object reference
    at android.renderscript.Element.U8_4(Element.java:580)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.agraham.reflection.Reflection.RunStaticMethod(Reflection.java:919)
    at com.dreamon.SelfieLight.preview._convolution5x5(preview.java:1348)
    at com.dreamon.SelfieLight.preview._seekbar1_valuechanged(preview.java:1953)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
    at anywheresoftware.b4a.BA$2.run(BA.java:297)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:145)
    at android.app.ActivityThread.main(ActivityThread.java:5832)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)

Solution:
Just had to initialize this:
B4X:
Sub InitGB()
    Dim Obj1 As Reflector
    Dim args(1) As Object
    Dim types(1) As String
    'RenderScript rs = RenderScript.create(getApplicationContext());
    args(0) =  Obj1.GetContext
    types(0) = "android.content.Context"
    rs.Target = Obj1.RunStaticMethod("android.renderscript.RenderScript","create", args, types)
End Sub
and call it in Activity_Create
 
Last edited:
Top