如何在 Rect 边界框内裁剪和调整图像部分的大小?

How to crop and resize the section of an Image within a Rect bounding box?

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

我见过 this answer 本来可以的,但是 ThumbnailUtils.extractThumbnail() 不能使用 4 个坐标的 Rect 并且它相对于图像的中心,而脸部的边界框可能在其他地方。

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())。


编辑: 我已经清理了一些旧文本,因为它变得难以抗拒。 实际上有效:我只是忘了删除一段我自己的代码,它已经将相同的 ImageProxy 转换为 Bitmap 并且它一定导致读取了一些内部缓冲区,直到结束,所以要么手动倒回它,要么完全删除那些无用的代码。

然而,即使 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
}

我们将提供更好的方法来处理使用 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 转换为Bitmap,并将其旋转为直立。面部检测的边界框应直接应用于位图,这意味着您应该能够使用 Rect 边界框裁剪位图。