Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Getting Started with CameraX

Caren
July 03, 2019

Getting Started with CameraX

Caren

July 03, 2019
Tweet

More Decks by Caren

Other Decks in Technology

Transcript

  1. Camera Development can be difficult and frustrating • Supporting different

    API versions • Providing consistency across devices
  2. Camera Development can be difficult and frustrating • Supporting different

    API versions • Providing consistency across devices • Understanding the complex camera API
  3. Camera Development can be difficult and frustrating • Supporting different

    API versions • Providing consistency across devices • Understanding the complex camera API CameraX support library aims to help solve these problems
  4. CameraX • Backwards compatible to L (90% of devices) •

    Consistent behavior across devices • Easy to use APIs
  5. // attach output to view val previewConfig = PreviewConfig.Builder().build() .setTargetRotation(Surface.ROTATION_180)

    val preview = Preview(previewConfig) preview.setOnPreviewOutputUpdateListener { previewOutput: Preview.PreviewOutput? -> //your code here. e.g. use previewOutput?.surfaceTexture //and post to a GL renderer. } CameraX.bindToLifecycle(this as LifecycleOwner, preview)
  6. // attach preview to lifecycle val previewConfig = PreviewConfig.Builder().build() .setTargetRotation(Surface.ROTATION_180)

    val preview = Preview(previewConfig) preview.setOnPreviewOutputUpdateListener { previewOutput: Preview.PreviewOutput? -> //your code here. e.g. use previewOutput?.surfaceTexture //and post to a GL renderer. } CameraX.bindToLifecycle(this as LifecycleOwner, preview)
  7. // display preview on screen val previewConfig = PreviewConfig.Builder().build() .setTargetRotation(Surface.ROTATION_180)

    val preview = Preview(previewConfig) preview.setOnPreviewOutputUpdateListener { previewOutput: Preview.PreviewOutput? -> //your code here. e.g. use previewOutput?.surfaceTexture //and post to a GL renderer. } CameraX.bindToLifecycle(this as LifecycleOwner, preview)
  8. // attach output val imageAnalysisConfig = ImageAnalysisConfig.Builder() .setTargetResolution(Size(1280, 720)) .build()

    val imageAnalysis = ImageAnalysis(imageAnalysisConfig) imageAnalysis.setAnalyzer({ image: ImageProxy, rotationDegrees: Int -> val cropRect = image.cropRect // do some analysis })
  9. // attach image analysis & preview to lifecycle val imageAnalysisConfig

    = ImageAnalysisConfig.Builder() .setTargetResolution(Size(1280, 720)) .build() val imageAnalysis = ImageAnalysis(imageAnalysisConfig) imageAnalysis.setAnalyzer({ image: ImageProxy, rotationDegrees: Int -> val cropRect = image.cropRect // do some analysis }) CameraX.bindToLifecycle(this as LifecycleOwner, imageAnalysis, preview)
  10. // full setup to process images val imageAnalysisConfig = ImageAnalysisConfig.Builder()

    .setTargetResolution(Size(1280, 720)) .build() val imageAnalysis = ImageAnalysis(imageAnalysisConfig) imageAnalysis.setAnalyzer({ image: ImageProxy, rotationDegrees: Int -> val cropRect = image.cropRect // do some analysis }) CameraX.bindToLifecycle(this as LifecycleOwner, imageAnalysis, preview)
  11. // bind all use cases val imageCaptureConfig = ImageCaptureConfig.Builder() .setTargetResolution(Size(1280,

    720)) .build() val imageCapture = ImageCapture(imageCaptureConfig) CameraX.bindToLifecycle(this as LifecycleOwner, imageCapture, imageAnalysis, preview)
  12. // full setup to capture images val imageCaptureConfig = ImageCaptureConfig.Builder()

    .setTargetResolution(Size(1280, 720)) .build() val imageCapture = ImageCapture(imageCaptureConfig) CameraX.bindToLifecycle(this as LifecycleOwner, imageCapture, imageAnalysis, preview)
  13. // on user action fun onClick() { val file =

    File(..) imageCaptureUseCase.takePicture(file, object : ImageCaptureUseCase.OnImageSavedListener { override fun onError(error: ImageCaptureUseCase.UseCaseError, message: String, exc: Throwable?) { //insert your code here } override fun onImageSaved(file: File) { //insert your code here } }) }
  14. // on user action save a picture fun onClick() {

    val file = File(..) imageCapture.takePicture(file, object : ImageCaptureUseCase.OnImageSavedListener { override fun onError(error: ImageCaptureUseCase.UseCaseError, message: String, exc: Throwable?) { //insert your code here } override fun onImageSaved(file: File) { //insert your code here } }) }
  15. // save a picture on user action fun onClick() {

    val file = File(..) imageCapture.takePicture(file, object : ImageCapture.OnImageSavedListener { override fun onError(error: ImageCapture.UseCaseError, message: String, exc: Throwable?) { //insert your code here } override fun onImageSaved(file: File) { //insert your code here } }) }
  16. CameraX sample app • Under Android camera samples GitHub repo

    • Monitoring all repo issues and pull requests
  17. CameraX sample app • Under Android camera samples GitHub repo

    • Monitoring all repo issues and pull requests • Sample issues != CameraX library issues
  18. CameraX sample app (cont) • Very basic indeed • Preview,

    image capture and image analysis • Future work: vendor extensions and video record
  19. CameraX sample app • Very basic indeed • Preview, image

    capture and image analysis • Future work: vendor extensions and video record
  20. Handling state changes beyond Lifecycle • Preview output update (CameraX

    internals) • Layout (TextureView lifecycle) • Display (180 rotations, display removed / attached)
  21. Handling state changes beyond Lifecycle • Preview output update (CameraX

    internals) • Layout (TextureView lifecycle) • Display (180 rotations, display removed / attached) • Camera hardware (USB, retractable)
  22. Handling state changes beyond Lifecycle • Preview output update (CameraX

    internals) • Layout (TextureView lifecycle) • Display (180 rotations, display removed / attached) • Camera hardware (USB, retractable)
  23. // Preview output update listener val preview: Preview = ...

    val viewFinder: TextureView = ... preview.setOnPreviewOutputUpdateListener { previewOutput: Preview.PreviewOutput? -> // Remove it and re-add view (important!) val parent = viewFinder.parent as ViewGroup parent.removeView(viewFinder) parent.addView(viewFinder, 0) // Update internal Surface object viewFinder.surfaceTexture = previewOutput.surfaceTexture // Apply preview output transformations // TODO: Use PreviewOutput textureSize and rotationDegrees here }
  24. // Preview output update listener val preview: Preview = ...

    val viewFinder: TextureView = ... preview.setOnPreviewOutputUpdateListener { previewOutput: Preview.PreviewOutput? -> // Remove it and re-add view (important!) val parent = viewFinder.parent as ViewGroup parent.removeView(viewFinder) parent.addView(viewFinder, 0) // Update internal Surface object viewFinder.surfaceTexture = previewOutput.surfaceTexture // Apply preview output transformations // TODO: Use PreviewOutput textureSize and rotationDegrees here }
  25. // Preview output update listener val preview: Preview = ...

    val viewFinder: TextureView = ... preview.setOnPreviewOutputUpdateListener { previewOutput: Preview.PreviewOutput? -> // Remove it and re-add view (important!) val parent = viewFinder.parent as ViewGroup parent.removeView(viewFinder) parent.addView(viewFinder, 0) // Update internal Surface object viewFinder.surfaceTexture = previewOutput.surfaceTexture // Apply preview output transformations // TODO: Use PreviewOutput textureSize and rotationDegrees here }
  26. // Preview output update listener val preview: Preview = ...

    val viewFinder: TextureView = ... preview.setOnPreviewOutputUpdateListener { previewOutput: Preview.PreviewOutput? -> // Remove it and re-add view (important!) val parent = viewFinder.parent as ViewGroup parent.removeView(viewFinder) parent.addView(viewFinder, 0) // Update internal Surface object viewFinder.surfaceTexture = previewOutput.surfaceTexture // Apply preview output transformations // TODO: Use PreviewOutput textureSize and rotationDegrees here }
  27. // Preview output update listener val preview: Preview = ...

    val viewFinder: TextureView = ... preview.setOnPreviewOutputUpdateListener { previewOutput: Preview.PreviewOutput? -> // Remove it and re-add view (important!) val parent = viewFinder.parent as ViewGroup parent.removeView(viewFinder) parent.addView(viewFinder, 0) // Update internal Surface object viewFinder.surfaceTexture = previewOutput.surfaceTexture // Apply preview output transformations // TODO: Use PreviewOutput textureSize and rotationDegrees here }
  28. Handling state changes beyond Lifecycle • Preview output update (CameraX

    internals) • Layout (TextureView lifecycle) • Display (180 rotations, display removed / attached) • Camera hardware (USB, retractable)
  29. Handling state changes beyond Lifecycle • Preview output update (CameraX

    internals) • Layout (TextureView lifecycle) • Display (180 rotations, display removed / attached) • Camera hardware (USB, retractable)
  30. // Layout change listener val viewFinder: TextureView = ... viewFinder.addOnLayoutChangeListener

    { view, left, top, right, bottom, _, _, _, _ -> val newDimens = Size(right - left, bottom - top) // Apply preview output transformations // TODO: Use `newDimens` here }
  31. // Layout change listener val viewFinder: TextureView = ... viewFinder.addOnLayoutChangeListener

    { view, left, top, right, bottom, _, _, _, _ -> val newDimens = Size(right - left, bottom - top) // Apply preview output transformations // TODO: Use `newDimens` here }
  32. // Layout change listener val viewFinder: TextureView = ... viewFinder.addOnLayoutChangeListener

    { view, left, top, right, bottom, _, _, _, _ -> val newDimens = Size(right - left, bottom - top) // Apply preview output transformations // TODO: Use `newDimens` here }
  33. Handling state changes beyond Lifecycle • Preview output update (CameraX

    internals) • Layout (TextureView lifecycle) • Display (180 rotations, display removed / attached) • Camera hardware (USB, retractable)
  34. Handling state changes beyond Lifecycle • Preview output update (CameraX

    internals) • Layout (TextureView lifecycle) • Display (180 rotations, display removed / attached) • Camera hardware (USB, retractable)
  35. // Display listener val viewFinder: TextureView = ... val viewFinderDisplayId:

    Int = viewFinder.display.displayId val displayListener = object : DisplayManager.DisplayListener { override fun onDisplayAdded(displayId: Int) = Unit override fun onDisplayRemoved(displayId: Int) = Unit override fun onDisplayChanged(displayId: Int) { if (displayId == viewFinderDisplayId) { val display = viewFinder.display // Apply preview output transformations // TODO: Use `display.rotation` here } } }
  36. // Display listener val viewFinder: TextureView = ... val viewFinderDisplayId:

    Int = viewFinder.display.displayId val displayListener = object : DisplayManager.DisplayListener { override fun onDisplayAdded(displayId: Int) = Unit override fun onDisplayRemoved(displayId: Int) = Unit override fun onDisplayChanged(displayId: Int) { if (displayId == viewFinderDisplayId) { val display = viewFinder.display // Apply preview output transformations // TODO: Use `display.rotation` here } } }
  37. // Display listener val viewFinder: TextureView = ... val viewFinderDisplayId:

    Int = viewFinder.display.displayId val displayListener = object : DisplayManager.DisplayListener { override fun onDisplayAdded(displayId: Int) = Unit override fun onDisplayRemoved(displayId: Int) = Unit override fun onDisplayChanged(displayId: Int) { if (displayId == viewFinderDisplayId) { val display = viewFinder.display // Apply preview output transformations // TODO: Use `display.rotation` here } } }
  38. // Preview output transformation // Option 1: apply rotation to

    view finder (on top of previous transformations) val matrix: Matrix = ... matrix.postRotate(-rotationDegrees, centerX, centerY)
  39. // Preview output transformation // Option 1: apply rotation to

    view finder (on top of previous transformations) val matrix: Matrix = ... matrix.postRotate(-rotationDegrees, centerX, centerY) // Option 2: apply rotation to preview use case, which will trigger // Preview.OnPreviewOutputUpdateListener val preview: Preview = ... preview.setTargetRotation(display.rotation)
  40. // Preview output transformation // Option 1: apply rotation to

    view finder (on top of previous transformations) val matrix: Matrix = ... matrix.postRotate(-rotationDegrees, centerX, centerY) // Option 2: apply rotation to preview use case, which will trigger // Preview.OnPreviewOutputUpdateListener val preview: Preview = ... preview.setTargetRotation(display.rotation) // Use PreviewOutput.rotationDegrees in Preview.OnPreviewOutputUpdateListener // Alternatively, get the view's display and always use display.rotation
  41. Handling state changes beyond Lifecycle • Preview output update (CameraX

    internals) • Layout (TextureView lifecycle) • Display (180 rotations, display removed / attached) • Camera hardware (USB, retractable)
  42. Handling state changes beyond Lifecycle • Preview output update (CameraX

    internals) • Layout (TextureView lifecycle) • Display (180 rotations, display removed / attached) • Camera hardware (USB, retractable)
  43. Handling state changes beyond Lifecycle • Preview output update (CameraX

    internals) • Layout (TextureView lifecycle) • Display (180 rotations, display removed / attached) • Camera hardware (USB, retractable)