B4A Class RenderScript Intrinsics Function Example

Discussion in 'Additional libraries, classes and official updates' started by DrewG, Sep 8, 2013.

  1. DrewG

    DrewG Member Licensed User

    *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.basic4ppc.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)

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

        
    Dim time As Long
        time = 
    DateTime.Now

        
    Dim args(1As Object
        
    Dim types(1As 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(2As Object
        
    Dim types2(2As 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:

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

        
    Dim Obj1 As Reflector
        
    Dim time As Long
        time = 
    DateTime.Now
        
    Dim args(1As Object
        
    Dim types(1As 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(2As Object
        
    Dim types2(2As 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:

    Code:
    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: May 19, 2015
  2. urikupfer

    urikupfer Member Licensed User

    Hi drewG
    Can you please add more samples with the using of RenderScript Intrinsics.
    uri
     
  3. DrewG

    DrewG Member Licensed 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.basic4ppc.com/android/forum/threads/bitmaps-subs-and-garbage-collection.37660/
     
  4. DrewG

    DrewG Member Licensed User

    Added the 5x5 convo, its pretty powerful. Really wish there were intrinsics for morphological operations/structural elements, so that dilation/erosion could be done at such speeds.
     
  5. Lykaion

    Lykaion Member Licensed User

  6. DrewG

    DrewG Member Licensed User

    I don't know how to do that off the top of my head. The link you have supplied looks like the right direction, I would use inline Java rather than reflection. I haven't used RS for much lately, I have found OpenCV/JavaCV to be almost as fast and easier to work with.

    http://www.b4x.com/android/forum/threads/inline-javacv-opencv.53963/
     
  7. yiankos1

    yiankos1 Active Member Licensed User

    When i try to run convolution5x5 throws me this error. Do you know why?
    Code:
    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:
    Code:
    Sub InitGB()
        
    Dim Obj1 As Reflector
        
    Dim args(1As Object
        
    Dim types(1As 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: Dec 6, 2015
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice