New debug mode for extended live analysis overlay

This commit is contained in:
Pierre-Yves Nicolas
2025-07-02 08:52:59 +02:00
parent 1463ef9355
commit 9c9963845e
2 changed files with 60 additions and 20 deletions

View File

@@ -46,6 +46,7 @@ import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
@@ -149,17 +150,15 @@ fun bindCameraUseCases(
}
@Composable
fun AnalysisOverlay(liveAnalysisState: LiveAnalysisState) {
fun AnalysisOverlay(liveAnalysisState: LiveAnalysisState, debugMode: Boolean) {
val binaryMask = liveAnalysisState.binaryMask
if (binaryMask == null) {
return
}
val maskOverlay = replaceColor(binaryMask, Color.Black, Color.Transparent)
Canvas(modifier = Modifier.fillMaxSize()) {
drawImage(
maskOverlay.scale(size.width.toInt(), size.height.toInt()).asImageBitmap(),
colorFilter = ColorFilter.tint(Color(0x8000FF00), BlendMode.SrcIn)
)
if (debugMode) {
drawMask(this, binaryMask)
}
if (liveAnalysisState.documentQuad != null) {
val scaledQuad = liveAnalysisState.documentQuad.scaledTo(
fromWidth = binaryMask.width,
@@ -174,6 +173,15 @@ fun AnalysisOverlay(liveAnalysisState: LiveAnalysisState) {
}
}
private fun drawMask(drawScope: DrawScope, binaryMask: Bitmap) {
val maskOverlay = replaceColor(binaryMask, Color.Black, Color.Transparent)
val size = drawScope.size
drawScope.drawImage(
maskOverlay.scale(size.width.toInt(), size.height.toInt()).asImageBitmap(),
colorFilter = ColorFilter.tint(Color(0x8000FF00), BlendMode.SrcIn)
)
}
fun replaceColor(bitmap: Bitmap, toReplace: Color, replacement: Color): Bitmap {
val width = bitmap.width
val height = bitmap.height

View File

@@ -86,6 +86,7 @@ data class CameraUiState(
val liveAnalysisState: LiveAnalysisState,
val captureState: CaptureState,
val showDetectionError: Boolean,
val isDebugMode: Boolean
)
const val CAPTURED_IMAGE_DISPLAY_DURATION = 1500L
@@ -101,6 +102,7 @@ fun CameraScreen(
var previewView by remember { mutableStateOf<PreviewView?>(null) }
val pageIds by viewModel.pageIds.collectAsStateWithLifecycle()
val thumbnailCoords = remember { mutableStateOf(Offset.Zero) }
var isDebugMode by remember { mutableStateOf(false) }
val captureController = remember { CameraCaptureController() }
DisposableEffect(Unit) {
@@ -149,7 +151,12 @@ fun CameraScreen(
{ offset -> thumbnailCoords.value = offset }
)
},
cameraUiState = CameraUiState(pageIds.size, liveAnalysisState, captureState, showDetectionError),
cameraUiState = CameraUiState(
pageIds.size,
liveAnalysisState,
captureState,
showDetectionError,
isDebugMode),
onCapture = {
previewView?.bitmap?.let {
Log.i("MyScan", "Pressed <Capture>")
@@ -160,6 +167,7 @@ fun CameraScreen(
}
},
onFinalizePressed = onFinalizePressed,
onDebugModeSwitched = { isDebugMode = !isDebugMode },
thumbnailCoords = thumbnailCoords,
)
}
@@ -171,6 +179,7 @@ private fun CameraScreenScaffold(
cameraUiState: CameraUiState,
onCapture: () -> Unit,
onFinalizePressed: () -> Unit,
onDebugModeSwitched: () -> Unit,
thumbnailCoords: MutableState<Offset>,
) {
Box {
@@ -180,6 +189,7 @@ private fun CameraScreenScaffold(
pageList = pageList,
pageCount = cameraUiState.pageCount,
onFinalizePressed = onFinalizePressed,
onDebugModeSwitched = onDebugModeSwitched,
)
}
) { innerPadding ->
@@ -189,7 +199,9 @@ private fun CameraScreenScaffold(
.fillMaxSize()
) {
CameraPreviewWithOverlay(cameraPreview, cameraUiState)
if (cameraUiState.isDebugMode) {
MessageBox(cameraUiState.liveAnalysisState.inferenceTime)
}
CaptureButton(
onClick = onCapture,
modifier = Modifier
@@ -309,7 +321,7 @@ private fun CameraPreviewWithOverlay(
.height(height.dp)
) {
cameraPreview()
AnalysisOverlay(cameraUiState.liveAnalysisState)
AnalysisOverlay(cameraUiState.liveAnalysisState, cameraUiState.isDebugMode)
captureState.frozenImage?.let {
Image(
bitmap = it.asImageBitmap(),
@@ -358,7 +370,25 @@ fun CameraScreenFooter(
pageList: @Composable () -> Unit,
pageCount: Int,
onFinalizePressed: () -> Unit,
onDebugModeSwitched: () -> Unit,
) {
var tapCount by remember { mutableStateOf(0) }
var lastTapTime by remember { mutableStateOf(0L) }
val tapThreshold = 500L
val onPageCountClick = {
val currentTime = System.currentTimeMillis()
if (currentTime - lastTapTime < tapThreshold) {
tapCount++
if (tapCount >= 3) {
onDebugModeSwitched()
tapCount = 0
}
} else {
tapCount = 1
}
lastTapTime = currentTime
}
Column (modifier = Modifier.background(MaterialTheme.colorScheme.primaryContainer)) {
pageList()
BottomAppBar(
@@ -373,7 +403,8 @@ fun CameraScreenFooter(
) {
Text(
text = "$pageCount pages",
style = MaterialTheme.typography.bodyMedium
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.clickable(onClick = onPageCountClick)
)
Button (
@@ -432,9 +463,10 @@ private fun ScreenPreview(captureState: CaptureState) {
listState = LazyListState(),
)
},
cameraUiState = CameraUiState(pageCount = 4, LiveAnalysisState(), captureState, false),
cameraUiState = CameraUiState(pageCount = 4, LiveAnalysisState(), captureState, false, false),
onCapture = {},
onFinalizePressed = {},
onDebugModeSwitched = {},
thumbnailCoords = thumbnailCoords,
)
}