Fix viewfinder issues: resolve subject blurring during background blur and enable background replacement in live camera feed
This commit is contained in:
@@ -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
|
// 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) {
|
if (blurIntensity > 0f) {
|
||||||
val radius = (15 * blurIntensity).toInt().coerceIn(1, 15)
|
val radius = (15 * blurIntensity).toInt().coerceIn(1, 15)
|
||||||
return blurBitmap(capturedImage, radius)
|
return blurBitmap(capturedImage, radius)
|
||||||
|
|||||||
Reference in New Issue
Block a user