Capturing every frame to recognize text ARcore - Do i need to use semaphores?

236 Views Asked by At

I am developing an app in which I want to recognize text in real-time.

At first I was using onTapListener so whenever the user was tapping on the screen the current frame was being captured and after that the text recognition was called.

Right now I want to do this completely real-time so the user will not tap on the screen to capture the current frame. But every current frame is going to be captured until the moment the text of one captured current frame will be recognized.

For this reason, I created a global boolean field name locked that is initialized in false and I use it as a "locker" as you will see in a bit.

private boolean locked = false;

And in a method onUpdateFrame(FrameTime frameTime) I use the above global variable locked. When the first feature points are tracked I "lock" the update. So only the current thread gonna capture the current frame. And if the recognized data is null the I put locked = true so the next frame gonna be captured.

This is my code

 public void onUpdateFrame(FrameTime frameTime) {
        Frame frame = arFragment.getArSceneView().getArFrame();
        // If there is no frame, just return.
        if (frame == null) {
            return;
        }

        //Making sure ARCore is tracking some feature points, makes the augmentation little stable.
        if(frame.getCamera().getTrackingState()==TrackingState.TRACKING && !locked) {
            locked = true;
            if (mProgressDialog == null) {
            mProgressDialog = ProgressDialog.show(this, "Processing",
                    "OCR...", true);
        } else {
            mProgressDialog.show();
        }
        executor.execute(() -> {
            Bitmap b = captureImage();
            final String[] text = {getOCRResult(b)};   
        handler.post(() -> {
            if(text[0] != null && !text[0].equals("")){
                   doSomething();
            }
            else{
                   locked = false;
            }

    }

This is not working though. And my app is crashing immediately when is detecting the surface.

I am getting the following error, and the Toast that the error talks about it refers to a Toast that I have inside the method captureImage()

E/AndroidRuntime: FATAL EXCEPTION: pool-1-thread-1 Process: opencv.org, PID: 27860 java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()

I cant understand what I am doing wrong. I heard of semaphores and this is why I asked that on my question. Should i use semaphores , do i need something like that so my app will work. As i understand i need one thread anytime to do the capture of the current frame. Could someone help me i am a bit lost? thank you

1

There are 1 best solutions below

0
On

The reason you are getting this error is that you can't show a toast, or any UI, on a non-UI thread.

The usual way to handle this is to create a 'Handler' on the UI thread and send a message to its message queue asking it to post the thread.

You can see examples in both Java and Kotlin in this answer: Can't create handler inside thread that has not called Looper.prepare()

More info on Handler here: https://developer.android.com/reference/android/os/Handler