PreviewView is full screen, imageCapture bitmap to imageView is scaled down with black background

2,630 views
Skip to first unread message

Omri Nachmani

unread,
Apr 26, 2021, 7:20:55 PM4/26/21
to Android CameraX Discussion Group
Can't figure out how to get the "what you see is what you get" effect, where i take a full screen image capture, and then display it as is on an imageview fragment. Currently using camerax in one fragment and imageview in another. I convert imageproxy to bitmap. 
Attached image shows the previewView being full screen and captured image being scaled down
Code:
CameraX fragment 
@SuppressLint("UnsafeExperimentalUsageError")
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(safeContext)

cameraProviderFuture.addListener(Runnable {
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

// Preview
preview = Preview.Builder().build()
val aspectRatio = Rational(viewFinder.width, viewFinder.height)
val viewport = ViewPort.Builder(aspectRatio, preview!!.targetRotation).build()
imageCapture = ImageCapture.Builder().build()

// Select back camera
val cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()

try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()

// Bind use cases to camera
camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
preview?.setSurfaceProvider(viewFinder.surfaceProvider)
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}

}, ContextCompat.getMainExecutor(safeContext))

}

private fun takePhoto() {
// Get a stable reference of the modifiable image capture use case
val imageCapture = imageCapture ?: return

// Setup image capture listener which is triggered after photo has
// been taken
imageCapture.takePicture(ContextCompat.getMainExecutor(safeContext), object : ImageCapture.OnImageCapturedCallback() {
override fun onError(exc: ImageCaptureException) {
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}

@SuppressLint("UnsafeExperimentalUsageError")
override fun onCaptureSuccess(image: ImageProxy) {
val buffer: ByteBuffer = image.planes[0].buffer
val bytes = ByteArray(buffer.capacity())
buffer.get(bytes)
val bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.size, null)

image.close()
val rotation = image.imageInfo.rotationDegrees.toFloat()
findNavController().navigate(CameraXViewDirections.actionCameraXViewToReviewImageFragment(bitmapImage, rotation))
super.onCaptureSuccess(image)

ImageView Fragment:

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = DataBindingUtil.inflate<FragmentReviewImageBinding>(
inflater, R.layout.fragment_review_image, container, false)
// Inflate the layout for this fragment
val args = reviewImageFragmentArgs.fromBundle(requireArguments())
binding.imageView.rotation = args.rotation
binding.imageView.setImageBitmap(args.bitmapImage)

ImageView XML:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
>

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/image_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>

<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true" />


Screenshot_20210426-191036.jpeg
Screenshot_20210426-191031.jpeg

Xi Zhang (张熹)

unread,
Apr 26, 2021, 8:08:10 PM4/26/21
to Omri Nachmani, Android CameraX Discussion Group
Hi Omri:

LifecycleCameraController provides the WYSIWYG feature. Please take a look and let us know if it fits your needs.  Caveat: WYSIWYG is not cost free. The captured image is cropped according to the visible area of the preview, which causes extra latency.

Thanks,

Xi

--
You received this message because you are subscribed to the Google Groups "Android CameraX Discussion Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to camerax-develop...@android.com.
To view this discussion on the web visit https://groups.google.com/a/android.com/d/msgid/camerax-developers/d7b792ea-afb4-4113-ae87-8c09a18678f2n%40android.com.

Eino-Ville Talvala

unread,
Apr 26, 2021, 8:25:13 PM4/26/21
to Xi Zhang (张熹), Omri Nachmani, Android CameraX Discussion Group
The other option is to make your preview View, whatever it is, have the exact aspect ratio of your ImageCapture use case when laid out. 

Omri Nachmani

unread,
Apr 26, 2021, 8:54:05 PM4/26/21
to Android CameraX Discussion Group, Xi Zhang, Android CameraX Discussion Group, Omri Nachmani
I dont see in this link where I can implement that feature. Can you provide some sample code? 

Omri Nachmani

unread,
Apr 26, 2021, 9:01:33 PM4/26/21
to Android CameraX Discussion Group, Eino-Ville Talvala, Omri Nachmani, Android CameraX Discussion Group, Xi Zhang
Eino I did the following:

imageCapture = ImageCapture.Builder()
.setTargetAspectRatio(viewFinder.width/viewFinder.height)
.build()

That did not solve the issue

Eino-Ville Talvala

unread,
Apr 26, 2021, 9:06:45 PM4/26/21
to Omri Nachmani, Android CameraX Discussion Group, Xi Zhang
You need to do the opposite - the View you're drawing your Preview to has to be the aspect ratio used for ImageCapture, not the other way around.  ImageCapture will only use sizes that the camera device itself supports, which is a limited set of things like 1080p, maximum sensor resolution (usually a 4:3 aspect ratio) and so on.  Picking a target aspect ratio that isn't a standard photographic ratio (16:9, 4:3, 2:3, etc) is unlikely to get you a size with that ratio.

This can be a pain to lay out, of course, which is why the alternative Xi mentions also exists, where the output of ImageCapture is cropped to match the somewhat-random aspect ratio of the preview.  But you do lose field of view as a result.


Xi Zhang (张熹)

unread,
Apr 26, 2021, 9:22:02 PM4/26/21
to Eino-Ville Talvala, Omri Nachmani, Android CameraX Discussion Group
Omri, 

As long as Viewport is set, the output of ImageCapture should be cropped. Actually your sample code already creates Viewport. All you need to do is use it in UseCaseGroup. e.g.

cameraProvider.bindToLifecycle(this, cameraSelector, UseCaseGroup.Builder().setViewport(viewport).addUseCase(imageCapture).addUseCase(preview).build())

CameraController is just a convenient way to set the viewport. If you are looking for tutorial for CameraController, we have a blog published: https://medium.com/androiddevelopers/camerax-learn-how-to-use-cameracontroller-e3ed10fffecf  Also CameraX' test app has sample code with CameraController. See: https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java


Omri Nachmani

unread,
Apr 26, 2021, 9:29:49 PM4/26/21
to Android CameraX Discussion Group, Xi Zhang, Omri Nachmani, Android CameraX Discussion Group, Eino-Ville Talvala
I just modified the code with the above and i still get a sized down image that is not full screen. Is there something in my XML file that's missing? 
PreviewView.jpeg
Message has been deleted

Omri Nachmani

unread,
Apr 26, 2021, 9:31:18 PM4/26/21
to Android CameraX Discussion Group, Omri Nachmani, Xi Zhang, Android CameraX Discussion Group, Eino-Ville Talvala
ImageView.jpegPreviewView.jpeg

Xi Zhang (张熹)

unread,
Apr 27, 2021, 11:55:48 AM4/27/21
to Omri Nachmani, Android CameraX Discussion Group, Eino-Ville Talvala
Omri, your code does not apply the crop rect to the captured image. You will need to crop the image using ImageProxy#getCropRect()
Reply all
Reply to author
Forward
0 new messages