Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android4OpenCV: setting resolution at startup

I'm using Android4OpenCV to do some live image processing, and I'd like to use the smallest resolution the camera can offer. The default resolution is the largest the camera can offer.

I'm looking at the 3rd example, which allows the user to change resolutions via a menu. I'd like to modify that example to change the resolution at startup instead of requiring the user go through the menu. To do that, I simply add two lines to the otherwise empty onCameraViewStarted() function:

public void onCameraViewStarted(int width, int height) {
    android.hardware.Camera.Size res = mOpenCvCameraView.getResolutionList().get(mOpenCvCameraView.getResolutionList().size()-1);
    mOpenCvCameraView.setResolution(res);
}

And the thing is, this works perfectly fine on my Galaxy Nexus, running Android 4.2.2. The app starts up, and the resolution is set correctly.

However, when I run the exact same app on a Nexus 7 tablet, running Android 5.1, the app hangs on the call to setResolution(). Actually it works okay one time, but then hangs the second time you try to run it- even if you completely exit the app, remove it from the running apps, or restart the device. Other users are reporting the same error as well, so it's not just the Nexus 7 device- in fact, my Galaxy Nexus seems to be the only device where this works.

Specifically, the application goes into the setResolution() function, which then calls org.opencv.android.JavaCameraView.disconnectCamera(), which looks like this:

(Note: this code is internal to the OpenCV4Android library, this is not my code)

protected void disconnectCamera() {
    /* 1. We need to stop thread which updating the frames
     * 2. Stop camera and release it
     */
    Log.d(TAG, "Disconnecting from camera");
    try {
        mStopThread = true;
        Log.d(TAG, "Notify thread");
        synchronized (this) {
            this.notify();
        }
        Log.d(TAG, "Wating for thread");
        if (mThread != null)
            mThread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        mThread =  null;
    }

    /* Now release camera */
    releaseCamera();
}

Looking at the logs, I can see that the thread gets stuck on the synchronized(this) line. The only other thing that synchronizes on that Object is the inner JavaCameraView.CameraWorker class, which is the mThread variable in the above code, started by the JavaCameraView class:

(Note: this code is internal to the OpenCV4Android library, this is not my code)

private class CameraWorker implements Runnable {

    public void run() {
        do {
            synchronized (JavaCameraView.this) {
                try {
                    JavaCameraView.this.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            if (!mStopThread) {
                if (!mFrameChain[mChainIdx].empty())
                    deliverAndDrawFrame(mCameraFrame[mChainIdx]);
                mChainIdx = 1 - mChainIdx;
            }
        } while (!mStopThread);
        Log.d(TAG, "Finish processing thread");
    }
}

I've tried futzing with that code, changing the notify() to notifyAll(), and maintaining a List of CameraWorker threads and joining each one. But no matter what, the app still hangs at the disconnectCamera() call.

My questions are:

  • How can I modify the third OpenCV4Android example so that its resolution is set at startup?

  • What is causing the app to hang?

  • Why does this work on some devices but not others?

Edit: I haven't received any comments or answers, so I've crossposted to the OpenCV forums here.

Edit 2: As per cyriel's suggestion, I've tried setting the resolution after several frames have gone by:

int frames = 0;
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {

    frames++;

    if(frames == 6){
        android.hardware.Camera.Size res = mOpenCvCameraView.getResolutionList().get(mOpenCvCameraView.getResolutionList().size()-1);
        mOpenCvCameraView.setResolution(res);

    }

    return inputFrame.rgba();
}

However, now this gets stuck in the same exact place, even on my Galaxy Nexus, which works if I set the resolution in the onCameraViewStarted() function. I've tried increasing the frame count to 7 and even 100, but I always get stuck in the same place.

like image 392
Kevin Workman Avatar asked May 07 '15 22:05

Kevin Workman


Video Answer


1 Answers

The most important question in your situation is whether it's working if you don't modify the code at all - are you able to change the resolution (via menu) without crashing the app?
If yes than the answer most likely is simple - it's the same bug in OpenCV as in Windows version: before changing camera resolution or fps (and most likely any property) you need to grab at least one (use 3-5 to be sure) frame before changing this property.
If no than most likely there is nothing you can do on your own - fill the bug report and wait for comments. The only alternative is to use other library to grab frames from camera and than convert it to OpenCV object.

like image 196
cyriel Avatar answered Oct 22 '22 00:10

cyriel