Implement soft edge alpha blending and viewfinder lag fix as described in 24_FIX_LAG.md
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user