Android 带有Camera2 API的图片非常暗
我在安卓上工作,我试图在不显示任何预览的情况下拍摄一张照片。我试图通过创建一个类来简化这个过程。它在工作,但是所有的照片都很暗。 这是我的班级:Android 带有Camera2 API的图片非常暗,android,image,api,camera,android-camera,Android,Image,Api,Camera,Android Camera,我在安卓上工作,我试图在不显示任何预览的情况下拍摄一张照片。我试图通过创建一个类来简化这个过程。它在工作,但是所有的照片都很暗。 这是我的班级: public class Cam { private Context context; private CameraManager manager; private CameraDevice camera; private CameraCaptureSession session; private ImageReader reader; public
public class Cam {
private Context context;
private CameraManager manager;
private CameraDevice camera;
private CameraCaptureSession session;
private ImageReader reader;
public static String FRONT="-1";
public static String BACK="-1";
private boolean available=true;
private String filepath;
private static final String NO_CAM = "No camera found on device!";
private static final String ERR_CONFIGURE = "Failed configuring session";
private static final String ERR_OPEN = "Can't open the camera";
private static final String CAM_DISCONNECT = "Camera disconnected";
private static final String FILE_EXIST = "File already exist";
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
public Cam(Context context) throws CameraAccessException {
this.context = context;
this.manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
String ids[] = manager.getCameraIdList();
if(ids.length==2){
BACK=ids[0];
FRONT=ids[1];
}
else if(ids.length==1){
BACK=ids[0];
}
else{
available=false;
throw new CameraAccessException(-1, NO_CAM);
}
}
public void takePicture(String camId, String filepath) throws CameraAccessException {
if(available){
this.filepath=filepath;
StreamConfigurationMap map = manager.getCameraCharacteristics(camId).get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new CompareSizesByArea());
reader=ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, 1);
reader.setOnImageAvailableListener(imageListener, null);
manager.openCamera(camId, cameraStateCallback, null);
}
else
throwError(NO_CAM);
}
private CameraDevice.StateCallback cameraStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
Cam.this.camera=camera;
try {
camera.createCaptureSession(Collections.singletonList(reader.getSurface()), sessionStateCallback, null);
} catch (CameraAccessException e) {
throwError(e.getMessage());
}
}
@Override
public void onDisconnected(CameraDevice camera) {
throwError(CAM_DISCONNECT);
}
@Override
public void onError(CameraDevice camera, int error) {
throwError(ERR_OPEN);
}
};
private CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
Cam.this.session=session;
try {
CaptureRequest.Builder request = camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
request.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
request.addTarget(reader.getSurface());
int rotation = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
request.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
session.capture(request.build(), captureCallback, null);
} catch (CameraAccessException e) {
throwError(e.getMessage());
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
throwError(ERR_CONFIGURE);
}
};
private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
throwError(failure.toString());
}
};
private ImageReader.OnImageAvailableListener imageListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
try {
File file = saveImage(image);
// Send file via a listener
closeCamera();
} catch (IOException e) {
throwError(e.getMessage());
}
reader.close();
}
};
private File saveImage(Image image) throws IOException {
File file = new File(filepath);
if (file.exists()) {
throwError(FILE_EXIST);
return null;
}
else {
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
FileOutputStream output = new FileOutputStream(file);
output.write(bytes);
image.close();
output.close();
return file;
}
}
static class CompareSizesByArea implements Comparator<Size> {
@Override
public int compare(Size lhs, Size rhs) {
return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
}
}
private void closeCamera(){
if(session!=null) {session.close();}
if(reader!=null) {reader.close();}
if(camera!=null) {camera.close();}
}
当图片可用时,侦听器会阻止main活动,但我删除了代码以清除一点
我不知道我做错了什么,照片真的很暗。也许是一面旗帜什么的。。。任何帮助都将不胜感激
编辑:
工人阶级:
示例:也许您可以尝试打开自动曝光模式和自动白平衡:
request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
request.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO);
我希望它会有所帮助:)如果您发送给相机的唯一捕获请求是最终图片的请求,这并不奇怪 相机自动曝光、对焦和白平衡程序通常需要一秒或两秒的流缓冲区,然后才能收敛到良好的效果 虽然您不需要在屏幕上绘制预览,但这里最简单的方法是首先运行一个针对虚拟SurfaceTexture的重复请求一两秒钟,然后启动JPEG捕获。 您可以只对JPEG捕获进行流式处理,但JPEG捕获速度较慢,因此需要较长的收敛时间(此外,与典型预览相比,相机实现更可能存在重复JPEG捕获并获得良好曝光的错误) 因此,使用随机纹理ID参数创建虚拟SurfaceTexture:
private SurfaceTexture mDummyPreview = new SurfaceTexture(1);
private Surface mDummySurface = new Surface(mDummyPreview);
并将曲面包含在会话配置中。配置会话后,创建一个针对虚拟预览的预览请求,并在收到N个捕获结果后,提交所需JPEG的捕获请求。您可能想尝试使用N,但大约30帧就足够了
请注意,您仍然没有处理以下问题:
- 锁定AF以确保JPEG图像清晰
- 如果您想使用闪光灯,请运行AE precapture以允许闪光灯测光
- 有一些方法让用户知道他们将捕获什么,因为没有预览,他们无法将设备瞄准任何东西
这里的Camera2基本示例中包括AF锁定和预许可触发序列:,因此您可以查看它们的功能。在我的情况下,仅配置FPS可以帮助我。不要忘了将它放到
CaptureRequest.Builder
预览,也不要忘了放到CaptureRequest.Builder
captureBuilder。像往常一样,FPS10或15帧足够拍照和预览
捕获生成器
// This is the CaptureRequest.Builder that we use to take a picture.
final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
...
setupFPS(captureBuilder);
预览生成器:
// We set up a CaptureRequest.Builder with the output Surface.
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
...
// set FPS rate
setupFPS(mPreviewRequestBuilder);
其中setupFPS:
private void setupFPS(CaptureRequest.Builder builder){
if(fpsRange != null) {
builder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);
}
}
和FPS的初始化,包括:
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
try {
Range<Integer>[] ranges = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
if(ranges != null) {
for (Range<Integer> range : ranges) {
int upper = range.getUpper();
Log.i(TAG, "[FPS Range Available]:" + range);
if (upper >= 10) {
if (fpsRange == null || upper < fpsRange.getUpper()) {
fpsRange = range;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
Log.i(TAG, "[FPS Range] is:" + fpsRange);
CameraCharacteristics characteristics=manager.getCameraCharacteristics(cameraId);
试一试{
Range[]ranges=characteristics.get(摄影机特性.控制\可用\目标\ FPS\范围);
如果(范围!=null){
用于(范围:范围){
int upper=range.getUpper();
Log.i(标记“[FPS范围可用]:”+范围);
如果(上限>=10){
if(fpsRange==null | | upper
它们只是比预期的颜色暗,还是实际上是黑色的?如果没有像太阳这样的强大光源直接进入光电传感器,图像几乎看不见,几乎是黑色的。例如,这是一张用本机应用程序拍摄的照片:这是用我的应用程序拍摄的照片:我尝试了各种方法在棉花糖api23上拍摄这张照片。似乎你不能附加一个虚拟的表面(我只能制作一个黑色的图片)。如果可能,请张贴适用于您的代码。我没有棒棒糖装置。谢谢你。感谢您的回复,但不幸的是,它没有起作用:(新尝试:也许自动白平衡有帮助?我编辑了我的帖子;)谢谢您的完整回复!我现在就要试试这个,我会让你不断更新的@omaflak是否可以发布工作示例?感谢you@eddy是否可以发布工作示例?非常感谢。我正在努力使这项工作,但没有运气,所以far@eddy你在安卓6上测试过代码吗?似乎如果我只附加虚拟曲面,就不会创建图像。看起来Android 6中唯一的方法就是创建一个暗图像(没有预览)。很抱歉,伙计们,我更改了我的帐户,我没有看到你的消息。我为它创建了一个库,请检查代码:
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
try {
Range<Integer>[] ranges = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
if(ranges != null) {
for (Range<Integer> range : ranges) {
int upper = range.getUpper();
Log.i(TAG, "[FPS Range Available]:" + range);
if (upper >= 10) {
if (fpsRange == null || upper < fpsRange.getUpper()) {
fpsRange = range;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
Log.i(TAG, "[FPS Range] is:" + fpsRange);