如何在 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 时的图像处理。
它将ImageProxy 转换为Bitmap,并将其旋转为直立。面部检测的边界框应直接应用于位图,这意味着您应该能够使用 Rect 边界框裁剪位图。
使用 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 时的图像处理。
它将ImageProxy 转换为Bitmap,并将其旋转为直立。面部检测的边界框应直接应用于位图,这意味着您应该能够使用 Rect 边界框裁剪位图。