Menu

Use SourceAFIS on Android Studio

WittayaSud
2017-12-19
2019-12-20
1 2 > >> (Page 1 of 2)
  • WittayaSud

    WittayaSud - 2017-12-19

    Hello there,

            try
            {
                File fileprobe = new File(Dir + "//probe.bmp");
                byte[] probeImage = new byte[(int) fileprobe.length()];
                new FileInputStream(fileprobe).read(BytesfileProbe);
                File fileprobe = new File(Dir + "//candidate.bmp");
                byte[] candidateImage = new byte[(int) fileprobe.length()];
                new FileInputStream(fileprobe).read(BytesfileProbe);
    
                //**** Start SourceAFIS ****//
                FingerprintTemplate probe = new FingerprintTemplate(probeImage);
                FingerprintTemplate candidate = new FingerprintTemplate(candidateImage);
    
                FingerprintMatcher matcher = new FingerprintMatcher(probe);
                double score = matcher.match(candidate);
    
                Toast.makeText(MainActivity.this, String.valueOf(score) ,Toast.LENGTH_LONG).show();
            }catch (Exception ex){
                Toast.makeText(MainActivity.this,  ex.toString(),Toast.LENGTH_LONG).show();
            }
    

    My application crash before "FingerprintTemplate probe = new FingerprintTemplate(probeImage);"

    What am I wrong?

    p.s. sourceafis-2.2.0.jar version and all images as bmp format 320*480px 500dpi

    Regard
    Wittaya

     
  • Robert Važan

    Robert Važan - 2017-12-19

    Stack trace?

     
  • WittayaSud

    WittayaSud - 2017-12-20

    Sorry, I don't know, my app just close, its didnt jump to exception line or any code line.
    its seem to be not call on FingerprintTemplate probe = new FingerprintTemplate(probeImage);

    regard

     
  • Łeonardo Stefani

    Hey WittayaSud. I had the same problem, my application was crashing in FingerprintTemplate

    I made some changes, to be compatible with Android.

    Considerations

    1 - FingerprintTemplate.java

    Method readImage(byte[] serialized) --- it uses java.awt.image.BufferedImage and Android don't have this

    2 - MatchBuffer.java

    private static final ThreadLocal<MatchBuffer> local --- it uses ThreadLocal.withInitial(MatchBuffer::new) and ThreadLocal.withInitial() is only available on API Level 26

    • Changes that I made to be compatible:

    FingerprintTemplate.java
    - change readImage(byte[] serialized) to be protected
    MatchBuffer.java
    - change "private static final ThreadLocal<MatchBuffer> local" to:

    private static final ThreadLocal<MatchBuffer> local = new ThreadLocal<MatchBuffer>() {
        @Override
        protected MatchBuffer initialValue() {
            return new MatchBuffer();
        }
    };
    
    • In the android app, we need create a class that extends from FingerprintTemplate and override readImage() method (or you can implement there instead of a override)... and bellow of readImage() add a private method getRgbFromBitmap(Bitmap bitmap)
    @Override
    protected DoubleMap readImage(byte[] serialized) {
        Bitmap bitmap = BitmapFactory.decodeByteArray(serialized, 0, serialized.length);
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int[] pixels = getRgbFromBitmap(bitmap);
        DoubleMap map = new DoubleMap(width, height);
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                int pixel = pixels[y * width + x];
                int color = (pixel & 0xff) + ((pixel >> 8) & 0xff) + ((pixel >> 16) & 0xff);
                map.set(x, height - y - 1, 1 - color * (1.0 / (3.0 * 255.0)));
            }
        }
        return map;
    }
    
    private int[] getRgbFromBitmap(Bitmap bitmap)
    {
         int picw = bitmap.getWidth();
         int pich = bitmap.getHeight();
    
         int[] pix = new int[picw * pich];
         bitmap.getPixels(pix, 0, picw, 0, 0, picw, pich);
    
         int r, g, b;
    
         // pix: {-1, -65794, -1, -65794, -65794, -65794, -1, -1, -460552, ...}
         for (int aPix : pix) {
             r = (aPix) >> 16 & 0xff;
             g = (aPix) >> 8 & 0xff;
             b = (aPix) & 0xff;
         }
    
         return pix;
    }
    
     
    • Mark B

      Mark B - 2019-08-13

      Hi sorry, can you elaborate this, I cant find a method readImage() in FingerprintTemplate.java

       
  • Robert Važan

    Robert Važan - 2018-03-15

    Thanks a lot Łeonardo.

     
  • Johan

    Johan - 2018-03-16

    HI
    Ive recently moved over to java from c# , where i was using source afis with great sucess.
    However being a novice with Android studio . I am hoping somebody has a sample android studio project that i can use as a reference, which compiles and matches any 2 fingers?

     
  • Azi Hassan

    Azi Hassan - 2018-03-26

    For those who managed to run it on Android, what was the performance like ?

    I ported it to an old SDK version (16) using the tricks outlined above as well as the StreamSupport library. Even though it worked, matching two fingerprints takes a minute and sometimes more. I narrowed it down to the template construction step, but I can't pinpoint the exact part that's causing it to be slow.

    I dumped the Android project on Github. Note that it's more of a scratchpad at this point* than a real project. The activity's source code is available here

    Below is the Logcat output after overriding FingerprintTransparency's log method to make use of Android Studio's logging capabilities :

    03-24 16:02:51.440 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: Preparing algorithm...
    03-24 16:02:51.710 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: decoded-image
    03-24 16:02:51.710 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: scaled-image
    03-24 16:02:51.710 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: block-map
    03-24 16:02:52.000 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: histogram
    03-24 16:02:52.840 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: smoothed-histogram
    03-24 16:02:52.990 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: clipped-contrast
    03-24 16:02:53.000 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: absolute-contrast-mask
    03-24 16:02:53.150 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: relative-contrast-mask
    03-24 16:02:53.150 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: combined-mask
    03-24 16:02:53.300 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: filtered-mask
    03-24 16:02:53.890 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: equalized-image
    03-24 16:03:01.430 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: pixelwise-orientation
    03-24 16:03:01.830 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: block-orientation
    03-24 16:03:01.880 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: smoothed-orientation
    03-24 16:03:03.210 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: parallel-smoothing
    03-24 16:03:04.450 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: orthogonal-smoothing
    03-24 16:03:04.600 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: binarized-image
    03-24 16:03:15.400 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: filtered-binary-image
    03-24 16:03:15.740 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: pixel-mask
    03-24 16:03:17.140 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: inner-mask
    03-24 16:03:17.140 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: ridges-binarized-skeleton
    03-24 16:03:17.910 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: ridges-thinned-skeleton
    03-24 16:03:19.810 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: ridges-traced-skeleton
    03-24 16:03:19.820 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: ridges-removed-dots
    03-24 16:03:19.840 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: ridges-removed-pores
    03-24 16:03:20.040 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: ridges-removed-gaps
    03-24 16:03:20.080 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: ridges-removed-tails
    03-24 16:03:20.080 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: ridges-removed-fragments
    03-24 16:03:20.080 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: valleys-binarized-skeleton
    03-24 16:03:20.860 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: valleys-thinned-skeleton
    03-24 16:03:22.780 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: valleys-traced-skeleton
    03-24 16:03:22.780 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: valleys-removed-dots
    03-24 16:03:22.800 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: valleys-removed-pores
    03-24 16:03:22.890 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: valleys-removed-gaps
    03-24 16:03:22.920 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: valleys-removed-tails
    03-24 16:03:22.920 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: valleys-removed-fragments
    03-24 16:03:22.960 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: skeleton-minutiae
    03-24 16:03:22.970 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: inner-minutiae
    03-24 16:03:23.000 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: removed-minutia-clouds
    03-24 16:03:23.000 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: top-minutiae
    03-24 16:03:23.830 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: edge-table
    03-24 16:03:23.830 27540-27646/com.example.lenovox220.fingerprintdemo I/SourceAFIS: Left fingerprint loaded
    
     

    Last edit: Azi Hassan 2018-03-27
  • Robert Važan

    Robert Važan - 2018-03-26

    Azi, 30s feature extraction means it is 500x slower than on my desktop. That's indicative of serious performance issue, for example running in interpreter mode (without compilation) or running on really crappy processor without hardware floating-point arithmetic.

     
    • Azi Hassan

      Azi Hassan - 2018-03-27

      I agree, it surprised me as well. The ported code doesn't behave like that on desktop. I tried building a release version but the problem persists, not sure if that's what you meant by it being interpreted. The CPU on my phone seems to be supporting hardware FP as evidenced by the output of /proc/cpu :

      Processor       : ARMv7 Processor rev 1 (v7l)
      BogoMIPS        : 666.41
      Features        : swp half thumb fastmult vfp edsp thumbee neon vfpv3
      CPU implementer : 0x41
      CPU architecture: 7
      CPU variant     : 0x0
      CPU part        : 0xc05
      CPU revision    : 1
      
      Hardware        : sc6820i
      Revision        : 0000
      Serial          : 415a58354e000115
      

      I did some googling and found out there were adb options to force the usage of the VFP, but they all involve the NDK.

       
  • Robert Važan

    Robert Važan - 2018-03-27

    One more thing that could kill performance is tiny cache combined with slow RAM. I am running out of ideas. For now, it's better to think of the Android support as very experimental. I would have to spend some time on it to make it work well.

     
    • Azi Hassan

      Azi Hassan - 2018-03-27

      No problem at all. I was only asking because I thought an Android port would only recquire minor modifications to the code and not to the algorithm itself. But I now see that it's more complicated than that.

       
  • Robert Važan

    Robert Važan - 2018-03-27

    Azi, how much work was it to backport to API level 16?

     
    • Azi Hassan

      Azi Hassan - 2018-03-27

      It only took a couple of days for me despite having very little Android experience.

      Most of the work involved replacing java.util.stream and java.util.function related code by their StreamSupport alternatives seeing as how those require a somewhat modern API.

      I also turned lambda calls into anonymous classes under Intellij's semi-automatic conversion, though it was just for good measure, Android Studio should be supporting them regardless of the API level.

      I then applied the change that was mentioned by Łeonardo Stefani to MatchBuffer.java and updated TemplateBuilder's readImage method with Android's BitmapFactory calls.

      Finally, I updated gradle's dependencies to include those of SourceAFIS.

       
  • Robert Važan

    Robert Važan - 2018-03-28

    Thanks, Azi. Seeing this, I think that if I do an Android port, it will target API level 24 and higher where lambdas are supported.

     
    • Azi Hassan

      Azi Hassan - 2018-03-29

      According to this, lambdas are supported in all SDK versions. From my understanding, Android Studio performs "desugaring" in order to unroll lambda expressions into anonymous classes, but I'm not sure.

      I thought I should add that the code ran flawlessly on an x86 emulator image with an SDK of level 22. Not sure if the x86 part is what caused it to run as it should or if it was the API level, but I don't have an Android 5.1 device to test on.

      Last but not least, I did some research and found a PDF where the author (Octavian Dospinescu) explains how they built a fingerprint recognition app for Android using an older version of SourceAFIS. Not sure if it could be of help.

       
  • Robert Važan

    Robert Važan - 2018-03-29

    I know about lambdas on lower API levels, but language support is only half of the solution.

    I think the x86 emulator has access to full power of the desktop it is running on. Test on recent Android device would tell us the real performance.

     
  • Robert Važan

    Robert Važan - 2018-03-30

    Binary image filter has been optimized in version 3.2, which should result in significantly faster feature extraction. Optimizing orientation detector, the other heavy CPU hog, is a bit harder, but it can be done too.

     

    Last edit: Robert Važan 2018-03-30
  • Johan

    Johan - 2018-04-13

    Hi Guys
    Im having similair issues with performance for template extraction.
    I am using android ver 19 which i cannot change and the templates take approx 10 seconds per finger to extract.

    My question . Once the extraction is done how long will it take to match , say 1 probe template to say 1000 candidate templates. Is the matching performance also slower than the .net version.
    Has anybody done some tests on this yet.

     
  • Johan

    Johan - 2018-04-16

    Hi
    Just some feedback on my question earlier(above).
    I tested the matcher on a DB of 200 fingerprints , and it takes approx 14 seconds to match against 200 sourceafis templates, stored in sqlite db.
    This is on an Android 4.4.2 platform android

     
  • Quamarul Islam

    Quamarul Islam - 2019-05-16

    I am getting the following error in Android Atudio:

    Verifier rejected class com.machinezoo.sourceafis.FingerprintTransparency

     
    • Robert Važan

      Robert Važan - 2019-05-16

      @Quamarul Islam Please create new thread if you need to discuss new question.

       
  • Mark B

    Mark B - 2019-08-13

    Hi guys, I'm having trouble applying this to android, I get also missing librarys specially in BufferedImage, what should I do?

     
    • Robert Važan

      Robert Važan - 2019-08-13

      If you have a specific problem with Android, could you start a new thread that describes that specific problem, including stack trace if applicable?

       
  • Robert Važan

    Robert Važan - 2019-09-19

    FYI, SourceAFIS 3.6.0 runs on Android API level 24+.

     
1 2 > >> (Page 1 of 2)

Log in to post a comment.