首页 > 解决方案 > 如何在矩形边界框中裁剪和调整图像部分的大小?

问题描述

在使用 CameraX 和 MLKit 检测到人脸后,我需要将图像传递给自定义 TFLite 模型(我正在使用这个),该模型检测面罩。该模型接受 224x224 像素的图像,因此我需要取出对应的部分并ImageProxy#getImage()相应地Face#getBoundingBox()调整其大小。

我已经看到了这个答案,它可能很好,但ThumbnailUtils.extractThumbnail()不能使用Rect4 个坐标,并且它相对于图像的中心,而面部的边界框可能在其他地方。

TFLite 模型接受如下输入:

val inputFeature0 = TensorBuffer
    .createFixedSize(intArrayOf(1, 224, 224, 3), DataType.FLOAT32)
    .loadBuffer(/* the resized image as ByteBuffer */)

请注意,ByteBuffer将具有224 * 224 * 3 * 4字节大小(其中 4 是DataType.FLOAT32.byteSize())。


编辑:我已经清理了一些旧文本,因为它变得不堪重负。下面建议的代码实际上是有效的:我只是忘记删除我自己的一段代码,该代码已经将其转换ImageProxyBitmap,它一定会导致一些内部缓冲区被读取到最后,所以要么需要手动倒带,要么完全删除无用的代码。

但是,即使cropRect应用到ImageProxy和底层Image,生成的位图仍然是全尺寸的,所以必须做其他事情。该模型仍在返回NaN值,因此我将尝试一段时间的原始输出。

fun hasMask(imageProxy: ImageProxy, boundingBox: Rect): Boolean {
    val model = MaskDetector.newInstance(context)
    val inputFeature0 = TensorBuffer.createFixedSize(intArrayOf(1, 224, 224, 3), DataType.FLOAT32)

    // now the cropRect is set correctly but the image itself isn't
    // cropped before being converted to Bitmap
    imageProxy.setCropRect(box)
    imageProxy.image?.cropRect = box

    val bitmap = BitmapUtils.getBitmap(imageProxy) ?: return false
    val resized = Bitmap.createScaledBitmap(bitmap, 224, 224, false)

    // input for the model
    val buffer = ByteBuffer.allocate(224 * 224 * 3 * DataType.FLOAT32.byteSize())
    resized.copyPixelsToBuffer(buffer)

    // use the model and get the result as 2 Floats
    val outputFeature0 = model.process(inputFeature0).outputFeature0AsTensorBuffer
    val maskProbability = outputFeature0.floatArray[0]
    val noMaskProbability = outputFeature0.floatArray[1]

    model.close()
    return maskProbability > noMaskProbability
}

标签: androidkotlintensorflow-liteandroid-cameraxgoogle-mlkit

解决方案


在使用 ML Kit 时,我们将提供更好的图像处理方式。

现在,你可以试试这个方法:https ://github.com/googlesamples/mlkit/blob/master/android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/BitmapUtils .java#L74

它将 ImageProxy 转换为位图,并将其旋转为直立。人脸检测的边界框应直接应用于位图,这意味着您应该能够使用 Rect 边界框裁剪位图。


推荐阅读