androidimage-processingcamera2

Nexus 5x Frames from preview are turned Camera2


I try to do some ImageProcessing on the current frame of the Preview in Android. In case of every other smartphone, it works pretty good. But now, I have to make the app accessible for the Nexus 5x.

There I get a 180 degree turned Image from the Preview. How can I fix that? Here my code for setting up my camera and the Preview:

private void resetCamera(int width, int height){
    Log.d(TAG, "Reset Camera!");
    CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        for (String cameraId : cameraManager.getCameraIdList()) {
            CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
            mSensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
            if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) {
                continue;
            }
            StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

            mImageReader = ImageReader.newInstance(width,
                    height,
                    ImageFormat.YUV_420_888,
                    10);
            mImageReader.setOnImageAvailableListener(mOnImageAvailableTrack,
                    mBackgroundHandler);

            mPreviewSize = getPreferredPreviewSize(map.getOutputSizes(SurfaceTexture.class), width, height);
            mCameraId = cameraId;
            return;
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

Preview:

private void createTrackingPreviewSession(){
    try{
        SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
        surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        Surface previewSurface = new Surface(surfaceTexture);
        mPreviewCaptureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mPreviewCaptureBuilder.addTarget(previewSurface);
        mPreviewCaptureBuilder.addTarget(mImageReader.getSurface());

        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        mPreviewCaptureBuilder.set(CaptureRequest.JPEG_ORIENTATION,
                getOrientation(rotation));

        mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, mImageReader.getSurface()),
                new CameraCaptureSession.StateCallback(){
                    @Override
                    public void onConfigured(CameraCaptureSession session) {
                        if(mCameraDevice == null){
                            return;
                        }
                        try{
                        Toast.makeText(getApplicationContext(), "Create Tracking Session", Toast.LENGTH_SHORT).show();
                            mPreviewCapture = mPreviewCaptureBuilder.build();
                            mCaptureSession = session;
                            mCaptureSession.setRepeatingRequest(
                                    mPreviewCapture,
                                    mSessionCaptureCallback,
                                    mBackgroundHandler
                            );
                        } catch(CameraAccessException e){
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onConfigureFailed(CameraCaptureSession session) {
                        Toast.makeText(
                                getApplicationContext(),
                                "create Camera session failed!",
                                Toast.LENGTH_SHORT
                        ).show();
                    }
                }, null);
    } catch(CameraAccessException e){
        e.printStackTrace();
    }
}

As you can see, I tried to use the fix for capturing a Image, but it didn't help I still get a turned Image from the Preview.

If it is possible, I would like a Solution, which tries to change the settings of the camera. I don't want to turn the Image by myself after I get it through the bound ImageReader.


Solution

  • After understanding your question properly I would try to do the following, if you aren't already. I think your problem does not reside in your previewCaptureSession but rather in your code to take a picture.

    I guess you are using a different CaptureRequest.Builder with the CameraDevice.TEMPLATE_STILL_CAPTURE template properly.

    For this Builder you have to set the JPEG orientation. As I already said in the comments, some camera devices have 90° and others a 270° rotation.

    To set the proper Orientation, implement the following two snippets.

    private static SparseIntArray ORIENTATIONS = new SparseIntArray();
    static{
        ORIENTATIONS.append(Surface.ROTATION_0, 0);
        ORIENTATIONS.append(Surface.ROTATION_90, 90);
        ORIENTATIONS.append(Surface.ROTATION_180, 180);
        ORIENTATIONS.append(Surface.ROTATION_270, 270);
    }
    
    private int sensorToDeviceRotation(CameraCharacteristics cameraCharacteristics, int deviceOrientation){
        int sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
        deviceOrientation = ORIENTATIONS.get(deviceOrientation);
        return (sensorOrientation + deviceOrientation + 360) % 360;
    }
    

    Or use your own logic / implementation.

    For your captureRequestBuilder, which you use to capture your images, set the JPEG_ORIENTATION as follows:

    int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
    captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, sensorToDevice(cameraCharacteristics, rotation));
    

    This is how I capture my images in my App, and my saved Images are properly rotated! If this is how you do it, I would suggest you add your code to actually take a picture, not only your preview Session.

    Hope that helps!