在Android中使用自动对焦连续拍照

时间:2016-05-24 12:04:29

标签: android multithreading android-asynctask android-camera

我在我的应用程序中制作了自定义相机视图。基本上,只要我的应用程序中的相机在聚焦后打开,我就需要做一些事情。

在我的Camera.Parameters中,我使用了FOCUS_MODE_CONTINUOUS_PICTURE,它按预期完美运行。现在,我需要从这个连续的自动对焦练习回调,在那里我可以拍摄当前的焦点图片并用它做点什么。

另一种方法是勾选一个计时器'技术,每隔一段时间后会触发的功能。然后,我可以在其中使用mCamera.autofocus(),拍照并完成我的工作。不幸的是,这被证明是一种非常糟糕的技术,因为自动聚焦会给不同的设备带来复杂性。

所以,我想知道,这将是什么是完美的解决方案。

更新:使用主题进行尝试后

我想做的是,只要应用程序位于前台,就可以反复自动对焦并拍照。

经过多次不同的尝试,这是我能够到达的最远,但还不够远。

请参阅可运行的代码:

public class OCRRunnable implements Runnable {

static final String TAG = "DBG_" + "OCRRunnable";

private final Object mPauseLockDummyObject;
private boolean mPaused;
private boolean mFinished;

Camera mCamera;

public OCRRunnable(Camera cameraParam) {
    mPauseLockDummyObject = new Object();
    mPaused = false;
    mFinished = false;

    mCamera = cameraParam;
}

@Override
public void run()
{
    if (mCamera != null) { // since the main activity may have been late opening the camera
        try {
            mCamera.autoFocus(new mAutoFocusCallback());
            Log.d(TAG, "run: mCamera.autofocus()");
        } catch (Exception e) {
            Log.e(TAG, "run: " + e.getMessage());
        }

        //sleep necessary //TODO: needs refinement
        //try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }

        //Runnable regulator
        synchronized (mPauseLockDummyObject) {
            while (mPaused) {
                try {
                    mPauseLockDummyObject.wait();
                } catch (InterruptedException e) {
                    Log.e(TAG, "run: " + e.getMessage());
                }
            }
        }
    }
}

/**
 * Call this on pause of the activity.
 */
public void onPause() {
    //Log.d(TAG, "onPause: called");
    synchronized (mPauseLockDummyObject) {
        mPaused = true;
    }
}

/**
 * Call this on resume of the activity
 */
public void onResume() {
    //Log.d(TAG, "onResume: called");
    synchronized (mPauseLockDummyObject) {
        mPaused = false;
        mPauseLockDummyObject.notifyAll();
    }
}

//////////////////////////////////////
protected class mAutoFocusCallback implements Camera.AutoFocusCallback {


    @Override
    public void onAutoFocus(boolean success, final Camera camera) {
        camera.takePicture(null, null, new Camera.PictureCallback() {

            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                Log.d(TAG, "onPictureTaken() called");

                /* NEED TO RUN THIS CODE PART REPETITIVELY */


                camera.cancelAutoFocus(); //be ready for next autofocus
                camera.startPreview(); //re-start cameraPreview since taking a picture stops it


                run(); //TODO


            }

        });
    }


}
}

这是我的相关片段:

public class ODFragment extends Fragment {

View rootView;
static final String TAG = "DBG_" + MainActivity.class.getName();

private Camera mCamera;
private CameraPreview mCameraPreview;
int ROIHeight;

FrameLayout frameLayout_cameraLens;
TextView words_container;

Thread ocrThread;
OCRRunnable ocrRunnable; //TODO: this may cause problems because mCamera is null as of this moment

public ODFragment() {}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    rootView = inflater.inflate(R.layout.fragment_od, container, false);

    //one time tasks
    words_container = (TextView) rootView.findViewById(R.id.words_container);
    setCameraViewDimensions();
    ocrThread = new Thread(ocrRunnable); //start it in onResume()





    return rootView;
}

@Override
public void onResume() {
    super.onResume();
    hookCamera();
}

@Override
public void onPause() {
    super.onPause();
    unhookCamera();
}

private void hookCamera() {
    try {
        // 1. open camera
        mCamera = Camera.open();
        // 2. initialize cameraPreview
        mCameraPreview = new CameraPreview(this.getActivity(), mCamera);
        // 3. add view to frameLayout
        frameLayout_cameraLens.addView(mCameraPreview);
        mCamera.startPreview();
        // 4. hook camera related listeners and threads
        ocrRunnable = new OCRRunnable(mCamera);
        ocrThread = new Thread(ocrRunnable);
        ocrThread.start();
        ocrRunnable.onResume();
    } catch (Exception e) {
        e.printStackTrace();
        Log.d(TAG, "Could not Camera.open(): " + e.getMessage());
    }

}

private void unhookCamera() {
    try {
        // -4. unhook camera related listeners ans threads
        ocrRunnable.onPause();
        ocrThread = null;
        ocrRunnable = null;
        // -3. remove view from frameLayout
        frameLayout_cameraLens.removeView(mCameraPreview);
        // -2. destroy cameraPreview
        mCameraPreview = null;
        // -1. close camera
        if (mCamera != null) {
            mCamera.release();
            mCamera = null;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void setCameraViewDimensions() {
    //calculate and set dimensions of cameraLens
    DisplayMetrics displaymetrics = new DisplayMetrics();
    getActivity().getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    int width = displaymetrics.widthPixels;
    int height = (int) (width * 1.3333333333333);
    //Log.d(TAG, "frameLayout_cameraLens dimensions: "+height+"x"+width);
    frameLayout_cameraLens = (FrameLayout) rootView.findViewById(R.id.frameLayout_cameraLens);
    frameLayout_cameraLens.getLayoutParams().width = width;
    frameLayout_cameraLens.getLayoutParams().height = height;
    frameLayout_cameraLens.requestLayout();

    //set height of ROI
    ROIHeight = height / 5;
    LinearLayout linearLayout = (LinearLayout) rootView.findViewById(R.id.ROI);
    linearLayout.getLayoutParams().height = ROIHeight;
    linearLayout.requestLayout();
}

}

有些观点:

  • 我认为camera.autofocus()发生在一个单独的线程本身。这就是为什么我没有在while(true)中放置run()循环,而是在mAutoFocusCallback
  • 的末尾调用了run()
  • 此时的错误是执行只到Log.d(TAG, "run: mCamera.autofocus()");一次。此外,Log.d(TAG, "onPictureTaken() called");甚至没有调过一次。

这是我的相关日志:

05-29 12:51:58.460 W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
05-29 12:51:58.573 D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
05-29 12:51:58.655 W/FragmentManager: moveToState: Fragment state for VTFragment{fd65ec0 #0 id=0x7f0c006d android:switcher:2131492973:1} not updated inline; expected state 3 found 2
05-29 12:51:58.962 D/DBG_CameraPreview: CameraPreview() initialized
05-29 12:51:59.079 D/DBG_OCRRunnable: run: mCamera.autofocus()
05-29 12:51:59.097 I/Adreno-EGL: <qeglDrvAPI_eglInitialize:379>: EGL 1.4 QUALCOMM build: Nondeterministic_AU_msm8974_LA.BF.1.1.3_RB1__release_AU (I3f4bae6ca5)
                             OpenGL ES Shader Compiler Version: E031.29.00.00
                             Build Date: 02/14/16 Sun
                             Local Branch: mybranch18261495
                             Remote Branch: quic/LA.BF.1.1.3_rb1.10
                             Local Patches: NONE
                             Reconstruct Branch: NOTHING
05-29 12:51:59.101 I/OpenGLRenderer: Initialized EGL, version 1.4
05-29 12:51:59.366 I/Choreographer: Skipped 46 frames!  The application may be doing too much work on its main thread.
05-29 12:51:59.556 I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@c66e1c1 time:44964952

1 个答案:

答案 0 :(得分:1)

使用mCamera.autofocus(callback) - 当焦点准备就绪时将触发回调。这是你拍照的机会。在onPictureTaken()中,您可能会调用mCamera.cancelAutoFocus(); mCamera.autofocus(callback);以允许相机重新对焦。

当然,每次相机聚焦时,您都可以选择不拍照。

要提高相机应用的性能,请务必致电Camera.open() on a background HandlerThread - 否则焦点和图片回调将阻止UI线程。当这些回调偶尔发生时,这可能是可以接受的,但在你的场景中,它们会经常被激活。

更新让我更清楚地呈现建议的循环(伪代码):

cameraInit() {
  Open camera, set FOCUS_MODE_CONTINUOUS_PICTURE
  camera.autofocus(autofocusCallback)
}

autofocusCallback() {
  if (it_is_time_to_take_picture) {
    takePicture(pictureCallback)
  }
  else {
    autofocusAgain()
  }
}

pictureCallback.onPictureTaken(image) {
  autofocusAgain()
  save image
}

autofocusAgain() {
  camera.cancelAutoFocus()
  wait(100ms)
  camera.autofocus(autofocusCallback)
}