2015-08-10 15 views
5

Sto lavorando su Android e sto cercando di catturare un'immagine senza visualizzare alcuna anteprima. Ho provato a semplificare il processo facendo una lezione. Funziona ma tutte le foto sono davvero buie. Qui è la mia classe:Le immagini con Camera2 API sono molto scure

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();} 
} 

Poi io chiamo l'oggetto Cam nella mia attività:

Cam cam = new Cam(MainActivity.this); 
cam.takePicture(Cam.BACK, "/sdcard/pic.jpg"); 

Un ascoltatore a prevenire la MainActivity quando l'immagine è a disposizione, ma ho rimosso il codice per cancellare un po ' .

Non so cosa sto sbagliando, le foto sono davvero buie. Forse una bandiera o qualcosa ... Qualsiasi aiuto sarà apprezzato.

EDIT: Working class: https://github.com/omaflak/Android-Camera2-Library/blob/master/ezcam/src/main/java/me/aflak/ezcam/EZCam.java

Esempio: https://github.com/omaflak/Android-Camera2-Library/blob/master/app/src/main/java/me/aflak/libraries/MainActivity.java

+0

Sono semplicemente più scuri del previsto, o in realtà neri? – rcsumner

+0

Se non c'è una sorgente di luce potente come il sole che entra direttamente nel sensore fotografico, l'immagine è quasi completamente nera. – omaflak

+1

Ad esempio, questa è una foto scattata con l'app nativa: http://i.imgur.com/tjvPonX.jpg?1 E questo è quello preso con la mia app: http://i.imgur.com/KceBGxY .jpg? 1 – omaflak

risposta

11

Se l'unica richiesta di acquisizione y o inviare alla fotocamera è quello per l'immagine finale, questo non è sorprendente.

Le routine di esposizione automatica, messa a fuoco e bilanciamento del bianco della fotocamera richiedono generalmente un secondo o due buffer di streaming prima di convergere in buoni risultati.

Mentre non è necessario disegnare l'anteprima sullo schermo, il metodo più semplice qui è di eseguire prima una richiesta ripetitiva che si rivolge a un SurfaceTexture fittizio per un secondo o due, e quindi sparare l'acquisizione JPEG. Si può semplicemente eseguire lo streaming dell'acquisizione JPEG, ma l'acquisizione JPEG è lenta, quindi sarà necessario un tempo più lungo per la convergenza (in più è più probabile che un'implementazione della telecamera abbia un bug con cattura JPEG ripetuta e una buona esposizione, rispetto ad una tipica anteprima).

Quindi, creare un SurfaceTexture manichino con un argomento tessitura ID casuale:

private SurfaceTexture mDummyPreview = new SurfaceTexture(1); 
private Surface mDummySurface = new Surface(mDummyPreview); 

e includono la superficie nella configurazione di sessione. Una volta configurata la sessione, crea una richiesta di anteprima che mira all'anteprima fittizia, e dopo che sono entrati i risultati N cattura, invia la richiesta di cattura per il JPEG che desideri. Ti consigliamo di sperimentare con N, ma probabilmente ~ 30 frame sono sufficienti.

nota che si sta ancora non si occupano di:

  • Blocco AF per assicurare un'immagine nitida per il vostro JPEG
  • esecuzione AE prima della cattura per consentire la misurazione flash, se si vuole consentire l'uso del flash
  • Avendo un modo per l'utente di sapere che cosa cattureranno, poiché non c'è un'anteprima, non possono mirare il dispositivo a qualcosa di molto bello.

la serratura e di trigger prima della cattura AF sequenze sono inclusi nel campione Camera2Basic qui: https://github.com/googlesamples/android-Camera2Basic, in modo da poter dare un'occhiata a ciò che coloro fanno.

+0

Grazie per la tua risposta completa! Ci proverò adesso, ti terrò aggiornato! – omaflak

+0

YESSSS !!! HA FUNZIONATO !!! : * D Grazie, davvero. – omaflak

+0

@omaflak è possibile postare l'esempio di lavoro? Grazie – user1611597

0

forse si può tentare di attivare la modalità di esposizione automatica e bilanciamento automatico del bianco:

request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); 
request.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO); 

spero che aiuterà :)

+0

Grazie per la risposta, ma purtroppo non ha funzionato :( – omaflak

+0

Nuovo tentativo: Forse il bilanciamento del bianco automatico aiuta? Ho modificato il mio post;) – esihemohen

+0

Grazie ancora, ma non ha funzionato neanche:/ – omaflak