【问题标题】:How to crop and resize the section of an Image within a Rect bounding box?如何在 Rect 边界框中裁剪和调整图像部分的大小?
【发布时间】:2021-05-08 00:11:12
【问题描述】:

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


编辑:我已经清理了一些旧文本,因为它变得不堪重负。 code suggested below 确实有效:我只是忘了删除我自己的一段代码,它已经将相同的 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
}

【问题讨论】:

  • 您好,您可以查看我在这里提供的解决方案stackoverflow.com/a/67348548/13300615。它应该可以帮助您在不将其转换为位图的情况下获得裁剪的图像。

标签: android kotlin tensorflow-lite android-camerax google-mlkit


【解决方案1】:

我们将在使用 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 边界框裁剪位图。

【讨论】:

  • 谢谢,我等不及 CameraX 未来的改进了。说“边界框应该直接应用于位图”,你的意思是在用InputImage.fromBitmap() 调用detector.process() 之后,我将不得不做imageProxy.cropRect = boundingBox 并再次将imageProxy 转换为位图?我确定我没有得到任何东西,因为它看起来有点令人费解。
  • 在修复了一些东西之后,您建议的代码终于可以工作了,但是图像仍然没有被裁剪。我已经用最近的变化更新了这个问题。
  • imageProxy.setCropRect(box) 不会为您裁剪图像。调整图片大小后,您可以使用developer.android.com/reference/android/graphics/…这个方法来裁剪带有检测到的边界框的图片。
  • 是的,我已经发现最好(也可能是唯一)要做的事情是从另一个位图的子区域创建一个新位图,例如 val cropped = Bitmap.createBitmap(bitmap, boundingBox.left, boundingBox.top, boundingBox.width(), boundingBox.height())
猜你喜欢
  • 2021-10-07
  • 2014-06-10
  • 1970-01-01
  • 1970-01-01
  • 2020-09-15
  • 1970-01-01
  • 2014-12-11
  • 1970-01-01
  • 2011-11-11
相关资源
最近更新 更多