You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Roboflow与Jetpack Compose中对齐漫画气泡检测矩形?

解决Jetpack Compose Canvas绘制漫画气泡矩形对齐问题

我正在实现漫画气泡检测功能:先截取设备屏幕,接收API返回的检测结果,再用Jetpack Compose的Canvas绘制矩形,但矩形始终无法和气泡正确对齐。

我的代码:

@Composable
internal fun ScreenShotDrawSpeech(
    bubbleDomain: BubbleDomain,
    modifier: Modifier = Modifier,
) {
    Canvas(
        modifier = modifier
            .fillMaxSize()
            .background(background_overlay),
        onDraw = {
            bubbleDomain.predictions.forEach { prediction ->
                val left = prediction.x
                val top = prediction.y

                drawRect(
                    color = Color.Red,
                    topLeft = Offset(left.toFloat(), top.toFloat()),
                    size = Size(prediction.width.toFloat(), prediction.height.toFloat()),
                    style = Stroke(width = 2f),
                )
            }
        },
    )
}

效果截图:
检测矩形错位的截图


问题核心

坐标系统不匹配:API返回的x/y/width/height是原始截图的像素坐标,而Compose Canvas的坐标基于当前布局的显示尺寸(经过设备密度缩放后的像素),两者尺寸比例不一致,直接使用原始坐标会导致错位。

解决方法

通过坐标缩放转换,将API返回的原始像素坐标适配到Canvas的显示坐标系中:

  1. 传递原始截图的真实像素尺寸到Composable
  2. 计算Canvas与原始截图的缩放比例,可选保持等比例避免变形
  3. 转换所有预测坐标和宽高后再绘制

修改后的代码:

@Composable
internal fun ScreenShotDrawSpeech(
    bubbleDomain: BubbleDomain,
    originalScreenshotSize: Size, // 原始截图的像素尺寸:width=截图宽,height=截图高
    modifier: Modifier = Modifier,
) {
    Canvas(
        modifier = modifier
            .fillMaxSize()
            .background(background_overlay),
        onDraw = {
            // 获取当前Canvas的实际显示尺寸
            val canvasWidth = size.width
            val canvasHeight = size.height

            // 计算等比例缩放系数(避免拉伸变形)
            val scaleX = canvasWidth / originalScreenshotSize.width
            val scaleY = canvasHeight / originalScreenshotSize.height
            val scale = min(scaleX, scaleY)

            // 计算居中偏移量(等比例缩放后留白的居中补偿)
            val offsetX = (canvasWidth - originalScreenshotSize.width * scale) / 2
            val offsetY = (canvasHeight - originalScreenshotSize.height * scale) / 2

            bubbleDomain.predictions.forEach { prediction ->
                // 转换原始坐标到Canvas坐标系
                val left = prediction.x.toFloat() * scale + offsetX
                val top = prediction.y.toFloat() * scale + offsetY
                val width = prediction.width.toFloat() * scale
                val height = prediction.height.toFloat() * scale

                drawRect(
                    color = Color.Red,
                    topLeft = Offset(left, top),
                    size = Size(width, height),
                    style = Stroke(width = 2f),
                )
            }
        },
    )
}

额外说明

  • 如果允许截图拉伸填充Canvas,可直接用scaleX和scaleY分别缩放,不需要取最小值和计算偏移
  • 确保originalScreenshotSize是截图的真实像素尺寸(比如截图Bitmap的宽高)
  • 若API返回的坐标原点不是左上角,需额外做坐标方向转换

内容的提问来源于stack exchange,提问作者OliverDamon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 09:51:21