From 06614f92e62866dcb60c2792170017ac10001590 Mon Sep 17 00:00:00 2001 From: locphamtran Date: Mon, 6 Jul 2026 18:14:50 +0700 Subject: [PATCH] Fix viewfinder issues: resolve subject blurring during background blur and enable background replacement in live camera feed --- .../java/com/photobooth/app/MainActivity.kt | 107 +++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/android-project/app/src/main/java/com/photobooth/app/MainActivity.kt b/android-project/app/src/main/java/com/photobooth/app/MainActivity.kt index 468319e..9a67fb1 100644 --- a/android-project/app/src/main/java/com/photobooth/app/MainActivity.kt +++ b/android-project/app/src/main/java/com/photobooth/app/MainActivity.kt @@ -1753,7 +1753,112 @@ class MainActivity : AppCompatActivity() { } // BỆNH PHÁP KHẮC PHỤC TRÌỆT ĐỂ LAG: Nếu là luồng Live Viewfinder, không chạy mô hình AI nặng - if (isStreamMode) { + if (isStreamMode && isAiSupported) { + try { + val segmenter = getImageSegmenter() + if (segmenter != null) { + val mpImage = com.google.mediapipe.framework.image.BitmapImageBuilder(capturedImage).build() + val segmentationResult = synchronized(aiInferenceLock) { + segmenter.segment(mpImage) + } + val categoryMaskOptional = segmentationResult.categoryMask() + if (categoryMaskOptional.isPresent) { + val categoryMask = categoryMaskOptional.get() + val categoryMaskBuffer = ByteBufferExtractor.extract(categoryMask) + categoryMaskBuffer.rewind() + + val w = categoryMask.width + val h = categoryMask.height + val bufferCapacity = categoryMaskBuffer.capacity() + + // Create and blur alpha mask + val alphaMask = FloatArray(w * h) + for (i in 0 until (w * h)) { + val classId = if (i < bufferCapacity) categoryMaskBuffer.get(i).toInt() else 0 + alphaMask[i] = if (classId in 1..5) 1.0f else 0.0f + } + blurAlphaMaskBox(alphaMask, w, h, radius = 3) + + // Prepare background (camera preview or custom background asset) + val baseBg = if (selectedBgAssetPath != null) { + try { + val bgInputStream = assets.open(selectedBgAssetPath!!) + val decodedBg = android.graphics.BitmapFactory.decodeStream(bgInputStream) + if (decodedBg != null) { + val tempScaled = android.graphics.Bitmap.createScaledBitmap(decodedBg, w, h, true) + if (tempScaled != decodedBg) decodedBg.recycle() + tempScaled + } else { + val solidBg = android.graphics.Bitmap.createBitmap(w, h, android.graphics.Bitmap.Config.ARGB_8888) + solidBg.eraseColor(android.graphics.Color.BLACK) + solidBg + } + } catch (e: Exception) { + val solidBg = android.graphics.Bitmap.createBitmap(w, h, android.graphics.Bitmap.Config.ARGB_8888) + solidBg.eraseColor(android.graphics.Color.BLACK) + solidBg + } + } else { + capturedImage + } + + val bgPixels = IntArray(w * h) + var blurredBg: android.graphics.Bitmap? = null + if (blurIntensity > 0f) { + val radius = (15 * blurIntensity).toInt().coerceIn(1, 25) + blurredBg = blurBitmap(baseBg, radius) + blurredBg.getPixels(bgPixels, 0, w, 0, 0, w, h) + } else { + baseBg.getPixels(bgPixels, 0, w, 0, 0, w, h) + } + + if (baseBg != capturedImage) { + baseBg.recycle() + } + + val fgPixels = IntArray(w * h) + val outputPixels = IntArray(w * h) + capturedImage.getPixels(fgPixels, 0, w, 0, 0, w, h) + + for (idx in 0 until (w * h)) { + val alpha = alphaMask[idx] + + val fgPixel = fgPixels[idx] + var fgR = android.graphics.Color.red(fgPixel) + var fgG = android.graphics.Color.green(fgPixel) + var fgB = android.graphics.Color.blue(fgPixel) + + val bgPixel = bgPixels[idx] + val bgR = android.graphics.Color.red(bgPixel) + val bgG = android.graphics.Color.green(bgPixel) + val bgB = android.graphics.Color.blue(bgPixel) + + // Color decontamination for edges + if (alpha > 0f && alpha < 1.0f) { + val grayIntensity = (fgR + fgG + fgB) / 3f + fgR = (fgR * alpha + grayIntensity * (1f - alpha)).toInt() + fgG = (fgG * alpha + grayIntensity * (1f - alpha)).toInt() + fgB = (fgB * alpha + grayIntensity * (1f - alpha)).toInt() + } + + val outR = (fgR * alpha + bgR * (1f - alpha)).toInt().coerceIn(0, 255) + val outG = (fgG * alpha + bgG * (1f - alpha)).toInt().coerceIn(0, 255) + val outB = (fgB * alpha + bgB * (1f - alpha)).toInt().coerceIn(0, 255) + + outputPixels[idx] = android.graphics.Color.rgb(outR, outG, outB) + } + + blurredBg?.recycle() + + val outputBitmap = android.graphics.Bitmap.createBitmap(w, h, android.graphics.Bitmap.Config.ARGB_8888) + outputBitmap.setPixels(outputPixels, 0, w, 0, 0, w, h) + return outputBitmap + } + } + } catch (e: Exception) { + // Ignore and fallback + } + if (blurIntensity > 0f) { val radius = (15 * blurIntensity).toInt().coerceIn(1, 15) return blurBitmap(capturedImage, radius)