android 对象检测-使用边界框在对象周围绘制矩形

kuuvgm7e  于 2023-04-28  发布在  Android
关注(0)|答案(2)|浏览(122)

首先,我想说明的是,我知道SO上已经发布了很多类似的问题,但没有一个提供解释其背后的步骤和逻辑的答案-只是简单地指向不同的教程库。
我已经经历了几个演示仓库,展示了如何做到这一点。大多数解决方案都有所不同,但可悲的是,它们包括5个类,这些类的代码非常复杂,但任务如此简单,所以我想寻找:
1.解决方案,做什么是需要-绘制矩形周围检测到的对象(多个),而活饲料正在运行
1.代码应该是简单的,优雅的和容易理解的
1.我也很想了解它背后的逻辑(这在demo repos中是不可能的)
所以这就是我的想法。
最大的挑战是转换检测到的边界框坐标,以便在Preview上显示它们时有意义。Preview图像的大小与输入图像不同,因此应相应地调整坐标。
现在,我有一个问题,绘制矩形有一个巨大的错误(矩形是从实际对象,所以坐标计算不正确)。

override fun draw(canvas: Canvas) {
    super.draw(canvas)

    // Get the dimensions of the preview image
    val previewWidth = previewImageSize.width
    val previewHeight = previewImageSize.height

    // Get the dimensions of the input image
    val inputWidth = inputImageSize.width
    val inputHeight = inputImageSize.height

    // Calculate the scaling factor for each dimension
    val scaleX: Float = previewWidth.toFloat() / inputWidth.toFloat()
    val scaleY: Float = previewHeight.toFloat() / inputHeight.toFloat()

    for (result in results) {
        val boundingBox = result.boundingBox

        val left = boundingBox.left * scaleX
        val top = boundingBox.top * scaleY
        val right = boundingBox.right * scaleX
        val bottom = boundingBox.bottom * scaleY

        // Draw bounding box around detected objects
        val drawableRect = RectF(left, top, right, bottom)
        canvas.drawRect(drawableRect, boxPaint)

        // Create text to display alongside detected objects
        val drawableText =
            result.categories[0].label + " " +
                    String.format("%.2f", result.categories[0].score)

        // Draw rect behind display text
        textBackgroundPaint.getTextBounds(drawableText, 0, drawableText.length, bounds)
        val textWidth = bounds.width()
        val textHeight = bounds.height()
        canvas.drawRect(
            left,
            top,
            left + textWidth + BOUNDING_RECT_TEXT_PADDING,
            top + textHeight + BOUNDING_RECT_TEXT_PADDING,
            textBackgroundPaint
        )

        // Draw text for detected object
        canvas.drawText(drawableText, left, top + bounds.height(), textPaint)
    }
}

其他信息:
输入图像大小:320x320(通过预览调整大小的图像,该图像被传递到模型内部以获取结果)
预览大小:1857x1080(1857作为高度)
从CameraX接收的ImageAnalsys图像:宽:640,高:480
ScaledX计算值:3.375
ScaledY计算值:5.803125
当前结果:

jv2fixgn

jv2fixgn1#

根据所显示的内容,看起来您正在使用MLKit对象检测,或者类似于TensorFlow的变体。
绝对推荐阅读:https://developers.google.com/ml-kit/vision/object-detection/androidhttps://developers.google.com/ml-kit/vision/object-detection/custom-models/android
接下来,在您的特定示例中,问题似乎是缩放到错误的图像。
正如您所注意到的,图像分析图像实际上是640x480,然后使用以下方法将其大小调整为320x320:

InputImage image = InputImage.fromMediaImage(
    mediaImage,imageProxy.getImageInfo().getRotationDegrees()
);

但没有提供细节。
之后,您将缩放到1080x1857图像,而不是640x480。这些结果看起来与您看到的失真类似。如果相对于640x480缩放,则框将是宽度的60%,高度的26%。基本上,一个小框并没有完全包围柠檬。
还请注意,它可能正在为您执行自动旋转校正。
如果你正在寻找一个“相当”简单的实现,那么:https://github.com/googlesamples/mlkit/tree/master/android/vision-quickstart
相对来说比较简单,只要你只关注物体检测部分,忽略其他部分。我从整个代码库开始进行文本和人脸识别,只去掉了我不想要的部分。

xfb7svmp

xfb7svmp2#

看起来宽高比没有通过CameraX输出和预览来保持。
尝试调整代码中的scaleXscaleY

// Calculate aspect ratios for input and preview image
val inputAspectRatio = inputWidth.toFloat() / inputHeight.toFloat()
val previewAspectRatio = previewWidth.toFloat() / previewHeight.toFloat()

// Determine the scales based on the right aspect ratios
val scaleX: Float
val scaleY: Float
if (previewAspectRatio > inputAspectRatio) {
    // If the preview has a wider aspect ratio, scale based on height
    scaleY = previewHeight.toFloat() / inputHeight.toFloat()
    scaleX = scaleY
} else {
    // Else if the input has a wider aspect ratio, scale based on width
    scaleX = previewWidth.toFloat() / inputWidth.toFloat()
    scaleY = scaleX
}

另外,要确保previewImageSizeinputImageSize变量的初始化值正确。如果值不正确,也可能导致绘制的矩形与实际对象偏离。

相关问题