Implement soft edge alpha blending and viewfinder lag fix as described in 24_FIX_LAG.md

This commit is contained in:
2026-07-06 18:08:17 +07:00
parent 4035aefda4
commit 9e739d3827
2 changed files with 192 additions and 15 deletions
@@ -1751,6 +1751,15 @@ class MainActivity : AppCompatActivity() {
}
return capturedImage
}
// 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 (blurIntensity > 0f) {
val radius = (15 * blurIntensity).toInt().coerceIn(1, 15)
return blurBitmap(capturedImage, radius)
}
return capturedImage
}
try {
val segmenter = getImageSegmenter()
@@ -1778,16 +1787,24 @@ class MainActivity : AppCompatActivity() {
val w = categoryMask.width
val h = categoryMask.height
val bufferCapacity = categoryMaskBuffer.capacity()
// --- THUẬT TOÁN 1: MASK SMOOTHING (LÀM MƯỢT BIÊN TOÀN DIỆN) ---
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
}
// Làm mượt mặt nạ để khử răng cưa và vết cắt cứng ở viền tóc/tai/vai
blurAlphaMaskBox(alphaMask, w, h, radius = 4)
// 2. Perform Monocular Depth Estimation via TFLite MiDaS model
val depthMap = runDepthInference(capturedImage)
// --- BƯỚC 1: TÍNH TIÊU CỰ ĐỐI TƯỢNG TỰ ĐỘNG BẰNG CẢ 2 AI (DYNAMIC AUTO-FOCUS) ---
// --- BƯỚC 1: TÍNH TIÊU CỰ ĐỐI TỰ ĐỘNG BẰNG CẢ 2 AI (DYNAMIC AUTO-FOCUS) ---
var totalDepthSum = 0f
var validPixelCount = 0
val bufferCapacity = categoryMaskBuffer.capacity()
// Quét nhanh qua ma trận để tìm chiều sâu thực tế của riêng cơ thể người (classId in 1..5)
for (y in 0 until h step 8) {
for (x in 0 until w step 8) {
@@ -1887,7 +1904,6 @@ class MainActivity : AppCompatActivity() {
for (y in 0 until h) {
for (x in 0 until w) {
val idx = y * w + x
val classId = if (idx < bufferCapacity) categoryMaskBuffer.get(idx).toInt() else 0
val maskX = (x * 256 / w).coerceIn(0, 255)
val maskY = (y * 256 / h).coerceIn(0, 255)
@@ -1896,8 +1912,6 @@ class MainActivity : AppCompatActivity() {
val relativeDistance = distance - objectFocalPoint
// --- THUẬT TOÁN 1: FEATHERING THEO CHIỀU SÂU & MEDIAPIPE ---
val isSubject = classId in 1..5
val focusAlpha = when {
relativeDistance <= 0f -> 1.0f
relativeDistance < fieldTolerance - 0.05f -> 1.0f
@@ -1908,15 +1922,8 @@ class MainActivity : AppCompatActivity() {
}
}
var alpha = if (isSubject) 1.0f else focusAlpha
if (alpha > 0.05f && alpha < 0.5f) {
alpha = cubicSmoothStep(0.05f, 0.5f, alpha)
} else if (alpha >= 0.5f) {
alpha = 1.0f
} else {
alpha = 0.0f
}
val maskAlpha = alphaMask[idx]
val alpha = kotlin.math.max(maskAlpha, focusAlpha)
val fgPixel = fgPixels[idx]
var fgR = android.graphics.Color.red(fgPixel)
@@ -1976,6 +1983,54 @@ class MainActivity : AppCompatActivity() {
}
}
private fun blurAlphaMaskBox(arr: FloatArray, w: Int, h: Int, radius: Int) {
if (radius <= 0) return
val temp = FloatArray(w * h)
// Horizontal pass
for (y in 0 until h) {
val rowOffset = y * w
var sum = 0f
val windowSize = radius * 2 + 1
// Initialize window sum
for (dx in -radius..radius) {
val px = dx.coerceIn(0, w - 1)
sum += arr[rowOffset + px]
}
temp[rowOffset] = sum / windowSize
// Slide window
for (x in 1 until w) {
val oldPixelX = (x - 1 - radius).coerceIn(0, w - 1)
val newPixelX = (x + radius).coerceIn(0, w - 1)
sum = sum - arr[rowOffset + oldPixelX] + arr[rowOffset + newPixelX]
temp[rowOffset + x] = sum / windowSize
}
}
// Vertical pass
for (x in 0 until w) {
var sum = 0f
val windowSize = radius * 2 + 1
// Initialize window sum
for (dy in -radius..radius) {
val py = dy.coerceIn(0, h - 1)
sum += temp[py * w + x]
}
arr[x] = sum / windowSize
// Slide window
for (y in 1 until h) {
val oldPixelY = (y - 1 - radius).coerceIn(0, h - 1)
val newPixelY = (y + radius).coerceIn(0, h - 1)
sum = sum - temp[oldPixelY * w + x] + temp[newPixelY * w + x]
arr[y * w + x] = sum / windowSize
}
}
}
private fun cubicSmoothStep(edge0: Float, edge1: Float, x: Float): Float {
val t = ((x - edge0) / (edge1 - edge0)).coerceIn(0f, 1f)
return t * t * (3f - 2f * t)