使用camera2 API无需预览即可捕获图片
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用camera2 API无需预览即可捕获图片相关的知识,希望对你有一定的参考价值。
我想要实现的是捕获图片而不显示预览,直接将输出发送到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();
}
}
答案
您应该在“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();
在session.capture()之后将调用“onImageAvailable”函数。
另一答案
由于我经常努力找到它是如何工作的,这里是一个可以处理图像数据的最小工作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;
}
}
另一答案
由于我一直在与CAMERA2 API挣扎很长时间,寻找如何在没有预览的情况下从设备上的所有可用摄像头拍照,我在GitHub上创建了一个完全符合你想要的项目(也许更多)https://github.com/hzitoun/android-camera2-secret-picture-taker
希望有帮助:)
以上是关于使用camera2 API无需预览即可捕获图片的主要内容,如果未能解决你的问题,请参考以下文章
如何使用Android中的Camera2 API在不预览的情况下拍摄多张照片?