Pytanie Rób zdjęcia bez podglądu za pomocą funkcji API camera2


Co chcę osiągnąć, to przechwytywanie obrazu bez pokazywania podglądu, wysyłanie bezpośrednio danych wyjściowych do ImageReader. Użyłem Przykład Camera2Basic jako punkt wyjścia. Jednak callback mojego ImageReader nigdy nie jest wywoływany, dlatego też żaden obraz nie jest wysyłany do niego Surface. Czy naprawdę muszę najpierw wyświetlić podgląd?

Jest to kod aparatu, który jest uporządkowany po przepływie asynchronicznych wywołań zwrotnych:

private ImageReader imageReader;
private Handler backgroundHandler;
private HandlerThread backgroundThread;
private String cameraId;
private CameraDevice cameraDevice;
private CameraCaptureSession cameraCaptureSession;
    @Override
    public void onCreate() {
        setupCamera2();
    }

    private void setupCamera2() {
        CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);

        try {

            for (String cameraId : manager.getCameraIdList()) {
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);

            if (characteristics.get(CameraCharacteristics.LENS_FACING) != CameraCharacteristics.LENS_FACING_FRONT) {
                continue;
            }

            this.cameraId = cameraId;

            int[] picSize = Settings.getPictureSize();
            int picWidth = picSize[0];
            int picHeight = picSize[1];

            imageReader = ImageReader.newInstance(picWidth, picHeight, ImageFormat.JPEG, 2);
            imageReader.setOnImageAvailableListener(onImageAvailableListener, backgroundHandler);
            }

        } catch (CameraAccessException | NullPointerException e) {
            e.printStackTrace();
        }
    }


    private void openCamera2() {
        CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        try {

            manager.openCamera(cameraId, cameraStateCallback, backgroundHandler);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }



    private final CameraDevice.StateCallback cameraStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice device) {
            cameraDevice = device;
            createCameraCaptureSession();
        }

        @Override
        public void onDisconnected(CameraDevice cameraDevice) {}

        @Override
        public void onError(CameraDevice cameraDevice, int error) {}
    };



    private void createCaptureSession() {
        List<Surface> outputSurfaces = new LinkedList<>();
        outputSurfaces.add(imageReader.getSurface());

        try {

            cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    cameraCaptureSession = session;
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession session) {}
            }, null);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }


    private final ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader reader) {
            createCaptureRequest();
        }
    };


    private void createCaptureRequest() {
        try {

            CaptureRequest.Builder requestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            requestBuilder.addTarget(imageReader.getSurface());

            // Focus
            requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

            // Orientation
            int rotation = windowManager.getDefaultDisplay().getRotation();
            requestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));

            cameraCaptureSession.capture(requestBuilder.build(), camera2Callback, null);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

13
2018-01-17 19:07


pochodzenie


Czy kiedykolwiek działałeś bez podglądu? - Kim HJ
@KimHJ Tak, sprawdź moją odpowiedź poniżej :) - Mitchapp


Odpowiedzi:


Należy przechwytywać zdjęcia w funkcji "onConfigured", ale nie w OnImageAvailable.

public void onConfigured(CameraCaptureSession session) {
            cameraCaptureSession = session;
            createCaptureRequest();
        }

W tej funkcji "onImageAvailable" należy zapisywać obrazy,

Image image = mImageReader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
try {
    save(bytes, file);
} catch (IOException e) {
    e.printStackTrace();
}
image.close();

Funkcja "onImageAvailable" zostanie wywołana po sesji session.capture ().


16
2018-01-19 07:29



Dzięki, działa. Pytanie nieco odbiegające od tematu: jak myślisz, jaki jest najlepszy format obrazu dla ImageReadera? - Alessandro Roaro
YUV. Przekształcenie w RGB to trudność, ale jakość jest trudna do dopasowania. - Sipty


Ponieważ bardzo się starałem dowiedzieć, jak to działa, oto minimalnie działająca usługa Android, która może przetwarzać dane obrazu. Prawdopodobnie potrzebuje trochę czasu po utworzeniu, zanim będziesz mógł zadzwonić uruchomić usługę!

import android.app.Service;
import android.content.Intent;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.media.Image;
import android.media.ImageReader;
import android.os.IBinder;
import android.util.Log;

import java.util.Arrays;

public class VideoProcessingService extends Service {
    private static final String TAG = "VideoProcessing";
    private static final int CAMERA = CameraCharacteristics.LENS_FACING_FRONT;
    private CameraDevice camera;
    private CameraCaptureSession session;
    private ImageReader imageReader;

    private CameraDevice.StateCallback cameraStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice camera) {
            VideoProcessingService.this.camera = camera;
        }

        @Override
        public void onDisconnected(CameraDevice camera) {}

        @Override
        public void onError(CameraDevice camera, int error) {}
    };

    private CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(CameraCaptureSession session) {
            VideoProcessingService.this.session = session;
            try {
                session.setRepeatingRequest(createCaptureRequest(), null, null);
            } catch (CameraAccessException e){
                Log.e(TAG, e.getMessage());
            }
        }

        @Override
        public void onConfigureFailed(CameraCaptureSession session) {}
    };

    private ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader reader){
            Image img = reader.acquireLatestImage();
            processImage(img);
            img.close();
        }
    };

    @Override
    public void onCreate() {
        CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
        try {
            manager.openCamera(getCamera(manager), cameraStateCallback, null);
            imageReader = ImageReader.newInstance(320, 240, ImageFormat.YUV_420_888, 30 * 600); //fps * 10 min
            imageReader.setOnImageAvailableListener(onImageAvailableListener, null);
        } catch (CameraAccessException e){
            Log.e(TAG, e.getMessage());
        }
    }

    /**
     *  Return the Camera Id which matches the field CAMERA.
     */
    public String getCamera(CameraManager manager){
        try {
            for (String cameraId : manager.getCameraIdList()) {
                CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
                int cOrientation = characteristics.get(CameraCharacteristics.LENS_FACING);
                if (cOrientation == CAMERA) {
                    return cameraId;
                }
            }
        } catch (CameraAccessException e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            camera.createCaptureSession(Arrays.asList(imageReader.getSurface()), sessionStateCallback, null);
        } catch (CameraAccessException e){
            Log.e(TAG, e.getMessage());
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        try {
            session.abortCaptures();
        } catch (CameraAccessException e){
            Log.e(TAG, e.getMessage());
        }
        session.close();
    }

    /**
     *  Process image data as desired.
     */
    private void processImage(Image image){
        //Process image data
    }

    private CaptureRequest createCaptureRequest() {
        try {
            CaptureRequest.Builder builder = camera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
            builder.addTarget(imageReader.getSurface());
            return builder.build();
        } catch (CameraAccessException e) {
            Log.e(TAG, e.getMessage());
            return null;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

13
2018-06-09 14:41



Mam wyjątek `Przyczyna: java.lang.NullPointerException: Próba wywołania metody wirtualnej 'void android.hardware.camera2.CameraDevice.createCaptureSession (java.util.List, android.hardware.camera2.CameraCaptureSession $ StateCallback, android.os. Handler) "na odwołaniu do obiektu zerowego" - iMom0
Podczas tworzenia ImageReadera nie trzeba ustawiać maksymalnych obrazów na 30 * 600. Bufory zostaną ponownie wykorzystane. Wszystko, co musisz zrobić, to zamknąć obraz uzyskiwany z ImageReadera. - alexhilton
Mały błąd: "if (cOrientation == CameraCharacteristics.LENS_FACING_BACK) {'zamiast" if (cOrientation == CAMERA) {' - RenaudBlue
@ iMom0 usługa nie działa zgodnie z bieżącym opublikowaniem. Zakłada on, że metoda onCreate jest wywoływana przed onStartCommand dla usługi. Sądzę, że Timon nie przetestował tego i opublikował go z pamięci. - RoundSparrow hilltx
Oto działająca wersja kodu gist.github.com/RoundSparrow/142b840ca86ba7a46639f23c5c0d195b - ma dodatkowe wyjście dziennika i kilka zmienionych nazw zmiennych. - RoundSparrow hilltx


Od dłuższego czasu zmagam się z API CAMERA2, szukając sposobu na robienie zdjęć bez podglądu od wszystkie dostępne kamery na urządzeniu, stworzyłem projekt na GitHub, który robi dokładnie to, czego chcesz (i może więcej) https://github.com/hzitoun/android-camera2-secret-picture-taker

enter image description here

Mam nadzieję, że pomogło :)


6
2018-01-29 00:08



Gdzie jest link zależności dla tego bro biblioteki. - viper
@viper nie ma biblioteki bro. Wystarczy skopiować usługę CaptureService github.com/hzitoun/android-camera2-secret-picture-taker/tree/... - Mitchapp