fix: sử dụng AI để nhận diện khuôn mặt và focus

This commit is contained in:
2026-07-06 17:25:21 +07:00
parent bc3b3533a7
commit 88fc095bdc
23 changed files with 2191 additions and 60 deletions
@@ -11,7 +11,8 @@ enum class EditAttribute {
BRIGHTNESS, CONTRAST, SATURATION, VIBRANCE, TEMPERATURE, TINT, // Nhóm 1: Cơ bản
CLARITY, DEHAZE, VIGNETTE_AMOUNT, // Nhóm 2: Nâng cao
FADED_BLACK_LEVEL, SHADOWS_TINT_R, SHADOWS_TINT_G, SHADOWS_TINT_B, // Nhóm 3: Tone Curve
GRAIN_AMOUNT, GRAIN_SIZE // Nhóm 4: Nhiễu hạt
GRAIN_AMOUNT, GRAIN_SIZE, // Nhóm 4: Nhiễu hạt
PORTRAIT_BLUR, BG_REPLACE // Nhóm 5: Tách nền AI
}
data class AttributeNode(
@@ -0,0 +1,74 @@
package com.photobooth.app
import android.graphics.BitmapFactory
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.card.MaterialCardView
data class BackgroundOption(
val id: String,
val name: String,
val assetPath: String?
)
class BackgroundOptionAdapter(
private val items: List<BackgroundOption>,
private val onBgSelected: (BackgroundOption) -> Unit
) : RecyclerView.Adapter<BackgroundOptionAdapter.ViewHolder>() {
private var selectedPosition = 0
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val cardBgOption: MaterialCardView = view.findViewById(R.id.cardBgOption)
val imgBgThumb: ImageView = view.findViewById(R.id.imgBgThumb)
val txtBgName: TextView = view.findViewById(R.id.txtBgName)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_background_option, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = items[position]
holder.txtBgName.text = item.name
if (item.assetPath == null) {
holder.imgBgThumb.setImageResource(R.drawable.ic_block_white)
} else {
try {
val inputStream = holder.itemView.context.assets.open(item.assetPath)
val bitmap = BitmapFactory.decodeStream(inputStream)
holder.imgBgThumb.setImageBitmap(bitmap)
} catch (e: Exception) {
holder.imgBgThumb.setImageDrawable(null)
}
}
val strokeWidthPx = (2 * holder.itemView.context.resources.displayMetrics.density).toInt()
if (position == selectedPosition) {
holder.cardBgOption.strokeColor = ContextCompat.getColor(holder.itemView.context, R.color.theme_primary)
holder.cardBgOption.strokeWidth = strokeWidthPx
} else {
holder.cardBgOption.strokeColor = ContextCompat.getColor(holder.itemView.context, R.color.theme_transparent)
holder.cardBgOption.strokeWidth = 0
}
holder.itemView.setOnClickListener {
val previousSelected = selectedPosition
selectedPosition = position
notifyItemChanged(previousSelected)
notifyItemChanged(selectedPosition)
onBgSelected(item)
}
}
override fun getItemCount(): Int = items.size
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="8dp" />
<solid android:color="#222222" />
<stroke android:width="1dp" android:color="#444444" />
</shape>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFF"
android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFF"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10-4.48 10-10S17.52,2 12,2zm0,3c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zm0,14.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z" />
</vector>
@@ -93,6 +93,15 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Lớp đè AI: Hiển thị kết quả tách nền thời gian thực -->
<ImageView
android:id="@+id/imgAiPreviewOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:visibility="gone"
android:contentDescription="AI Preview Overlay" />
<!-- Lớp đè lọc màu (Filter Overlay): Hiển thị màu Preset cổ điển -->
<ImageView
android:id="@+id/imgFilterOverlay"
@@ -110,6 +119,14 @@
android:scaleType="fitCenter"
android:contentDescription="Frame Overlay" />
<!-- Lớp chớp sáng màn hình khi chụp (Flash Effect) -->
<View
android:id="@+id/viewShutterFlash"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:visibility="gone" />
<!-- Số đếm ngược khi hẹn giờ chụp -->
<TextView
android:id="@+id/txtTimerCountdown"
@@ -138,7 +155,7 @@
app:layout_constraintTop_toBottomOf="@id/cameraContainer"
app:layout_constraintBottom_toTopOf="@id/bottomControlPanel">
<!-- Danh sách cuộn ngang -->
<!-- Danh sách cuộn ngang (Frames / Presets) -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvHorizontalTimeline"
android:layout_width="match_parent"
@@ -150,6 +167,56 @@
android:paddingEnd="16dp"
android:visibility="gone" />
<!-- Danh sách lựa chọn phông nền AI (Thay thế nền) -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvBackgroundOptions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal"
android:clipToPadding="false"
android:paddingStart="75dp"
android:paddingEnd="16dp"
android:visibility="gone" />
<!-- Thước đo Ruler cho Portrait Blur (Xóa nền) -->
<FrameLayout
android:id="@+id/panelRulerContainer"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="75dp"
android:visibility="gone">
<com.photobooth.app.RulerView
android:id="@+id/panelRulerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:id="@+id/layoutPanelRulerPointer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center">
<TextView
android:id="@+id/tvPanelRulerValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textColor="#FF9800"
android:textSize="12sp"
android:textStyle="bold"
android:layout_gravity="center_horizontal"/>
<ImageView
android:layout_width="12dp"
android:layout_height="12dp"
android:src="@drawable/ic_arrow_down_orange"
android:layout_gravity="center_horizontal"
android:contentDescription="Indicator" />
</LinearLayout>
</FrameLayout>
<!-- Khung nền đen che các item cuộn sang bên trái -->
<View
android:id="@+id/viewLeftDockBackground"
@@ -158,7 +225,7 @@
android:background="#000000"
android:visibility="gone" />
<!-- LỚP TRÊN: Chứa 2 nút chức năng chính (Gốc ở giữa, động chuyển sang trái) -->
<!-- LỚP TRÊN: Chứa 4 nút chức năng chính (Gốc ở giữa, động chuyển sang trái) -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/buttonsWrapper"
android:layout_width="match_parent"
@@ -176,7 +243,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/btnMainPreset"
app:layout_constraintHorizontal_chainStyle="packed"
android:layout_marginEnd="16dp"
android:layout_marginEnd="12dp"
android:contentDescription="Frame Selector" />
<!-- Nút Presets Màu -->
@@ -189,8 +256,36 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btnMainFrame"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintEnd_toStartOf="@id/btnMainPortraitBlur"
android:layout_marginEnd="12dp"
android:contentDescription="Preset Color Selector" />
<!-- Nút Xóa nền (Portrait Blur) -->
<ImageView
android:id="@+id/btnMainPortraitBlur"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/ic_attr_portrait_blur"
android:background="@android:color/transparent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btnMainPreset"
app:layout_constraintEnd_toStartOf="@id/btnMainBgReplace"
android:layout_marginEnd="12dp"
android:contentDescription="Portrait Blur Selector" />
<!-- Nút Thay nền (BG Replace) -->
<ImageView
android:id="@+id/btnMainBgReplace"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/ic_attr_bg_replace"
android:background="@android:color/transparent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btnMainPortraitBlur"
app:layout_constraintEnd_toEndOf="parent"
android:contentDescription="Background Replace Selector" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
@@ -298,6 +393,7 @@
<!-- Kim chỉ số 0 màu cam chính giữa cố định -->
<LinearLayout
android:id="@+id/layoutRulerPointer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cardBgOption"
android:layout_width="60dp"
android:layout_height="44dp"
android:layout_margin="3dp"
app:cardCornerRadius="4dp"
app:cardElevation="1dp"
app:strokeWidth="0dp"
app:cardBackgroundColor="#222222">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="2dp">
<ImageView
android:id="@+id/imgBgThumb"
android:layout_width="24dp"
android:layout_height="24dp"
android:scaleType="centerCrop"
android:contentDescription="Background Thumb" />
<TextView
android:id="@+id/txtBgName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="9sp"
android:singleLine="true"
android:ellipsize="end"
android:text="BG" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>