2015-08-10 19 views
5

Pracuję nad systemem Android i próbuję przechwycić obraz bez wyświetlania podglądu. Próbowałem uprościć proces, tworząc zajęcia. Działa, ale wszystkie zdjęcia są naprawdę bardzo ciemne. Oto moja klasa:Zdjęcia z interfejsem Camera2 API są naprawdę ciemne

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

Potem wywołać obiekt Cam w mojej działalności:

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

Słuchacz zapobiec główną działalność, gdy obraz jest dostępny, ale usunąłem kod, aby usunąć trochę .

Nie wiem, co robię źle, zdjęcia są naprawdę ciemne. Może flaga lub coś ... Każda pomoc zostanie doceniona.

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

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

+0

Czy są po prostu ciemniejsze niż się spodziewano, czy rzeczywiście czarne? – rcsumner

+0

Jeśli nie ma silnego źródła światła, takiego jak słońce bezpośrednio wpadające do czujnika, zdjęcie jest prawie niewidoczne prawie czarne. – omaflak

+1

Na przykład, jest to zdjęcie zrobione z natywną aplikacją: http://i.imgur.com/tjvPonX.jpg?1 A to jest zrobione z moją aplikacją: http://i.imgur.com/KceBGxY .jpg? 1 – omaflak

Odpowiedz

11

Jeśli jedyne żądanie przechwytywania y Wysyłasz do kamery to zdjęcie do ostatecznego zdjęcia, nic w tym dziwnego.

Automatyczne ustawianie ekspozycji kamery, ostrość i balans bieli zazwyczaj wymagają drugiego lub dwóch buforów strumieniowych, zanim osiągną dobre wyniki.

Podczas gdy nie trzeba narysować podglądu na ekranie, najprostszą metodą jest wykonanie najpierw powtarzającego się żądania, które będzie dotyczyło atrapa SurfaceTexture na sekundę lub dwie, a następnie odpalenie przechwytywania JPEG. Można po prostu przesyłać strumieniowo przechwytywanie JPEG, ale przechwytywanie JPEG jest powolne, więc będziesz potrzebować więcej czasu na konwergencję (plus jest to bardziej prawdopodobne, że implementacja kamery ma błąd z wielokrotnym przechwytywaniem JPEG i uzyskaniem dobrej ekspozycji, niż z typowym podglądem).

więc stworzyć atrapę SurfaceTexture z losową tekstury ID argumentu:

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

i obejmują powierzchnię w konfiguracji sesji. Po skonfigurowaniu sesji utwórz żądanie podglądu, które jest ukierunkowane na fałszywy podgląd, a po pojawieniu się N wyników przechwytywania, prześlij żądanie przechwytywania dla żądanego JPEG. Będziesz chciał eksperymentować z N, ale prawdopodobnie ~ 30 ramek wystarczy.

Pamiętaj, że nie jesteś jeszcze do czynienia z:

  • Blokowanie AF, aby zapewnić ostry obraz dla JPEG
  • Running AE precapture celu umożliwienia pomiaru błysku, jeśli chcesz, aby do użycia lampy błyskowej
  • Mając jakiś sposób, aby użytkownik wiedział, co przechwytuje, ponieważ nie ma podglądu, nie może skierować urządzenia na nic bardzo dobrze.

Sekwencje wyzwalacza AF i presetu są zawarte w przykładach Camera2Basic tutaj: https://github.com/googlesamples/android-Camera2Basic, dzięki czemu można rzucić okiem na to, co robią.

+0

Dziękuję za twoja pełna odpowiedź! Mam zamiar spróbować teraz, będę Cię na bieżąco! – omaflak

+0

YESSSS !!! ZADZIAŁAŁO !!! : * D Dziękuję, naprawdę. – omaflak

+0

@omaflak Czy można opublikować przykład roboczy? Dziękuję – user1611597

0

Być może można spróbować włączyć automatyczny tryb ekspozycji i automatycznego balansu bieli:

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

Mam nadzieję, że pomoże :)

+0

Dziękuję za odpowiedź, ale niestety to nie zadziałało :( – omaflak

+0

Nowa próba: Może automatyczny balans bieli pomaga? Zmieniono mój post;) – esihemohen

+0

Jeszcze raz dziękuję, ale to też nie zadziałało:/ – omaflak