设置 ImageAnalyzer 和 PreviewView 的宽高相同

Set width and height of ImageAnalyzer and PreviewView the same

我有一个简单的设置:

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...
}

问题是我从分析方法收到的图像分辨率比预览视图分辨率 (widht/height) 小得多,因此导致图像不是很好识别。

如果我使用预览视图的位图,我基本上可以获得整个屏幕的图片,这对分析来说效果更好,但我认为这是不好的做法?

所以我的问题是:是否可以设置我在上面尝试过的 ImageAnalyzer 的分辨率(例如 setTargetResolution)?

或者处理此类问题的最佳方法是什么?

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?

在某些设备上是可能的,例如,将两个分辨率都设置为 1080p。但是,不能保证它在任何地方都能正常工作,因为相机硬件可能不支持它。此外,根据您的使用场景,高分辨率图像分析也可能是一种不好的做法,因为分析通常不需要如此高分辨率。

请问为什么要求Preview和ImageAnalysis的分辨率一样?

我刚遇到同样的问题,我想为 PreviewView 和 ImageCapture 使用更高的分辨率,为 ImageAnalysis 使用更小的分辨率,但我希望它们在纵横比和内容上看起来相同。

然而,在某些特定分辨率下,ImageAnalysis 和 ImageCapture 中的图像看起来相同,但它们比 PreviewView 上的图像更宽。

我通过将 PreviewView 的 scaleType 设置为 FIT_CENTER 来解决这个问题,因为它的默认值是 FILL_CENTER,如果相机预览纵横比不正确,这将导致预览被裁剪与其容器不匹配:

previewView.scaleType = PreviewView.ScaleType.FIT_CENTER

并且,为确保 ImageAnalysis 纵横比尽可能接近 PreviewView:

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
}

最后,我可以得到小分辨率的图像进行分析,高分辨率的图像用于预览和捕获,具有相同的纵横比并且看起来相同!