Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how do I capture a single image with the Android Camera2 API?

Tags:

android

I am using the Android Camera2 API to capture and process an image. The image processing happens in reponse to a successful capture. The problem I am having is that the camera captures 2 images, I have been unable to change the code in the Camera2Basic sample to ensure only a single image is captured. The issue can be demonstrated by adding logging code to the ImageSaver.run() method in Camera2BasicFragment.java

public void run() {
    Log.d("Camera2", "Saving image");
    ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
    ...
}

Edit - after further investigation the issue appears to be in the implementation of the sample, rather than anything fundamental to the API. In the sample, the following code tracks the state changes of the camera,

 private void process(CaptureResult result) {
        switch (mState) {
            case STATE_PREVIEW: {
                // We have nothing to do when the camera preview is working normally.
                break;
            }
            case STATE_WAITING_LOCK: {
                int afState = result.get(CaptureResult.CONTROL_AF_STATE);
                if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
                        CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
                    // CONTROL_AE_STATE can be null on some devices
                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    if (aeState == null ||
                            aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
                        mState = STATE_WAITING_NON_PRECAPTURE;
                        /** CAPTURE 1 */
                        captureStillPicture();
                    } else {
                        runPrecaptureSequence();
                    }
                }
                break;
            }
            case STATE_WAITING_PRECAPTURE: {
                ...
                break;
            }
            case STATE_WAITING_NON_PRECAPTURE: {
                // CONTROL_AE_STATE can be null on some devices
                Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
                    mState = STATE_PICTURE_TAKEN;
                    /** CAPTURE 2 **/
                    captureStillPicture();
                }
                break;
            }
        }
    }

I have verified that both invocations of captureStillPicture result in an image being generated, and hence processed. I'm not entirely sure what the correct state transitions should be.

I am using a Motorola Nexus 6

like image 428
Andrew Marshall Avatar asked Feb 18 '15 14:02

Andrew Marshall


People also ask

Is Camera2 API deprecated?

Both CameraX and Camera2 support Android 5.0 (API level 21) and higher. Camera2 is the latest low-level Android camera package and replaces the deprecated Camera class.

How do you open camera through intent and display captured image?

This is done as follows: Intent camera_intent = new Intent(MediaStore. ACTION_IMAGE_CAPTURE); startActivityForResult(camera_intent, pic_id); Now use the onActivityResult() method to get the result, here is the captured image.

Should I enable Camera 2 API?

The main purpose of Camera2API is to improve camera quality by controlling some important camera features such as shutter speed, RAW shooting, white balance. First of all, we need to understand whether the Camera2API feature is enabled on our phone.


2 Answers

There does indeed seem to be a redundancy/error in the sample code. The simple solution is to change the line just before you've written /** CAPTURE 1 */ to

mState = STATE_PICTURE_TAKEN;

This case is only entered when all the settings are already right/converged, and so might as well initiate the still capture, as it does. It just wasn't recording that it did so.

like image 177
rcsumner Avatar answered Oct 17 '22 04:10

rcsumner


since your question I started reading and digging into it, and I believe that's the way it works. As per doc (link) says:

Each request will produce one CaptureResult and produce new frames for one or more target Surfaces

note that it says "frames". In plural.

Said that I believe you should only consider the last frame from inside onCaptureCompleted callback.

like image 45
Budius Avatar answered Oct 17 '22 03:10

Budius