4

I've got a simple setup:

preview = new Preview.Builder().build();
preview.setSurfaceProvider(mPreviewView.createSurfaceProvider());
imageAnalysis = new ImageAnalysis.Builder().setTargetResolution(new Size(mPreviewView.getWidth(),mPreviewView.getHeight())).build();
imageAnalysis.setAnalyzer(executor, new PaperImageAnalyser());

ImageAnalyzer:

@SuppressLint("UnsafeExperimentalUsageError")
@Override
public void analyze(@NonNull ImageProxy imageProxy) {
    Image mediaImage = imageProxy.getImage();

    if (mediaImage != null) {
        InputImage image = InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees());
        Log.e("madieaimage",mediaImage.getHeight() + " and with" + mediaImage.getWidth()); //480 and with640
        Log.e("inputimage", image.getHeight() + " and width" + image.getWidth()); //480 and width640
        Log.e("imageproxy", image.getHeight() + " and width" + image.getWidth()); //480 and width640
        Log.e("cameraimp previewview ", CameraImp.mPreviewView.getBitmap().getHeight() + " and widht" +  CameraImp.mPreviewView.getBitmap().getWidth()); //2145 and widht1080
        image =  InputImage.fromBitmap(CameraImp.mPreviewView.getBitmap(),0); //analyzes much better cause resolution is set but its not good practise right?
    }
    
    //analyze with image...
}

The issue is that the resolution of the Image I receive from the analyze method is much smaller than the previewview resoltion (widht/height), so that causes that images are not really good recongnized.

If I use the bitmap of the previewview I get the entire pic of the screen basically which works better for the analyzation, but thats bad practice I assume?

So my question is: Is it possible to set the resolution of the ImageAnalyzer (eg setTargetResolution) I tried above?

Or what would the best way be to deal with such an issue?

Nummer Eins
  • 199
  • 1
  • 8

2 Answers2

1

If I use the bitmap of the previewview I get the entire pic of the screen basically which works better for the analyzation, but thats bad practice I assume?

Yes this is bad practice performance-wise because buffer copy is very expensive.

So my question is: Is it possible to set the resolution of the ImageAnalyzer (eg setTargetResolution) I tried above?

It's possible on some of the devices if you e.g. set both resolution to 1080p. However there is no guarantee it will work everywhere because it might not be supported by the camera hardware. Also, depending on your usage scenario, a high resolution image analysis could also be a bad practice because analysis usually do not require such a high resolution.

May I ask why do you need the resolution of Preview and ImageAnalysis to be the same?

Xi 张熹
  • 10,492
  • 18
  • 58
  • 86
  • I need the resolution to be the "same" since using the imageProxy image returns wrong rect coordinates with a smaller resolution.. the rect is misaligned/outside of the actual object. Which lloks like this for example: https://pasteboard.co/K0dMhyj.jpg or https://pasteboard.co/K0dMA4W.jpg if I use the bitmap of previewview i receive better resulsts basically – Nummer Eins May 03 '21 at 19:10
  • It's not always possible for ImageAnalysis and Preview to have the same resolution, at least not on all devices. In which case you will need to transform the coordinates manually to align them. If you don't care about performance, you can get a Bitmap from PreviewView and use it for analysis. Then it will be WYSIWYG. – Xi 张熹 May 04 '21 at 18:26
  • hmm, I see. to bad. I might suffer from performance as my analyzer runs 24/7, maybe I might just change it so the analyzer analyzes just a static image, would safe performance at least. thanks for the answer bro – Nummer Eins May 04 '21 at 19:56
  • For me the solution with the bad performance produces a problem because I can not access the bitmap of the previewview outside of the MainThread. CameraX will crash if you try to do this. How did you achieve this? – Janusz Aug 11 '22 at 14:03
1

I just faced the same problem, I'd like to use higher resolution for PreviewView and ImageCapture, and smaller resolution for ImageAnalysis, but i want them to looks same in both aspect ratio and contents.

However, in some specifical resolution, images from ImageAnalysis and ImageCapture looks same, but they are wider than image on PreviewView.

I solved this by set scaleType of PreviewView to FIT_CENTER, as its default value is FILL_CENTER, which would cause the preview to be cropped if the camera preview aspect ratio does not match that of its container:

previewView.scaleType = PreviewView.ScaleType.FIT_CENTER

And, to ensure ImageAnalysis aspect ratio is as close to the PreviewView as possible:

val highSize = Size(3000, 4000)
val preview = Preview.Builder().setTargetResolution(highSize).build()
val imgCaptured = ImageCapture.Builder().setTargetResolution(highSize).build()
preview.setSurfaceProvider(previewView.surfaceProvider)
// bind empty lifycycle with id to get camera
val supportSizes = getSupportedSizes(camera, 0)
val analysisSize = getNearestSize(supportSizes, 480, 640, 30f)
val analyzer = ImageAnalysis.Builder()
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .setOutputImageRotationEnabled(true)
            .setTargetResolution(analysisSize).build()
analyzer.setAnalyzer(...)
cameraProvider.unbindAll()
val camera = cameraProvider.bindToLifecycle(lifecycle, cameraSelector, preview, imgCaptured, analyzer)


fun getSupportedSizes(camera: Camera, device: Int): Array<Size!>{
    val cInfo = camera.cameraInfo
    val camChars = Camera2CameraInfo.extractCameraCharacteristics(cInfo)
    val configs: StreamConfigurationMap? =
        camChars.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
    if (configs == null) {
        Log.i(TAG, "get camera out sizes fail, config empty")
        return
    }
    val sensorRotate = camChars.get(CameraCharacteristics.SENSOR_ORIENTATION) ?: 0
    return configs.getOutputSizes(ImageFormat.JPEG)
}

fun getNearestSize(sizes: Array<Size!>, inWidth: Int, inHeight: Int, aspectWeight: Float = 1f): Size? {
    if (inWidth <= 0 || inHeight <= 0 || device !in cameraInfoMap) return null
    val requireArea = inWidth * inHeight
    val requireAspect = inHeight * 1f / inWidth
    var bestSize: Size? = null
    var minDiff: Float = 10000f
    Log.i(TAG, "find near size for aspect: ${requireAspect}, $inWidth * $inHeight, weight: $aspectWeight")
    for (size in sizes) {
        val curArea = size.width * 1f * size.height
        val curAspect = size.height * 1f / size.width
        val curDiff = abs(curAspect - requireAspect) * aspectWeight + abs(curArea / requireArea - 1)
        if (bestSize == null || minDiff > curDiff) {
            Log.i(TAG, "better size: $size, diff: $curDiff")
            bestSize = size
            minDiff = curDiff
        }
    }
    return bestSize
}

Finally, I can get small resolution image for analysis, and high resolution for preview and capture, which has same aspect ratio and looks same!

liber
  • 166
  • 1
  • 7