Захват изображения без предварительного просмотра с помощью API камеры2
То, что я хочу достичь, - это захват изображения без предварительного просмотра, отправка напрямую на ImageReader
.
В качестве отправной точки я использовал Camera2Basic example.
Однако обратный вызов моего ImageReader
никогда не вызывается, поэтому на его Surface
изображение не отправляется.
Действительно ли мне нужно сначала просмотреть предварительный просмотр?
Это код камеры, который упорядочен после потока асинхронных обратных вызовов:
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();
}
}
Ответы
Ответ 1
Вы должны делать снимки в функции onConfigured, но не onImageAvailable.
public void onConfigured(CameraCaptureSession session) {
cameraCaptureSession = session;
createCaptureRequest();
}
В этой функции "onImageAvailable" вы должны сохранять изображения,
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();
Функция "onImageAvailable" будет вызываться после session.capture().
Ответ 2
Поскольку я много разбирался в том, как это работает, вот минимальная работающая служба Android, которая может обрабатывать данные изображения. Это, вероятно, потребуется некоторое время после создания, прежде чем вы сможете вызвать запуск службы, хотя!
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;
}
}
Ответ 3
Поскольку я долгое время боролся с CAMERA2 API, я искал, как делать снимки без предварительного просмотра из всех доступных камер на устройстве. создал проект на GitHub, который делает именно то, что вы хотите (и, возможно, больше)
https://github.com/hzitoun/android-camera2-secret-picture-taker
![введите описание изображения здесь]()
Надеюсь, что это помогло:)