From c4fd35bfe4bf11d3c1cad8ec0d0d58cc0f0b47db Mon Sep 17 00:00:00 2001 From: maxinyu Date: Mon, 1 Jun 2026 11:38:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=BA=E8=84=B8=E8=AF=86=E5=88=AB=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../liveVideo/AlarmLogActivity.kt | 2 +- .../login/FaceLoginActivity.kt | 3 - .../personal/FaceManagementActivity.kt | 9 +- .../view/FaceOverlayView.kt | 93 +++++++++++-------- .../main/res/layout/face_login_activity.xml | 34 ++++--- .../res/layout/face_verification_activity.xml | 27 +++--- 6 files changed, 91 insertions(+), 77 deletions(-) diff --git a/app/src/main/java/com/example/defenseapplication/liveVideo/AlarmLogActivity.kt b/app/src/main/java/com/example/defenseapplication/liveVideo/AlarmLogActivity.kt index ae28e5f..1690dbe 100644 --- a/app/src/main/java/com/example/defenseapplication/liveVideo/AlarmLogActivity.kt +++ b/app/src/main/java/com/example/defenseapplication/liveVideo/AlarmLogActivity.kt @@ -216,7 +216,7 @@ class AlarmLogActivity : AppCompatActivity() { val response = RetrofitNetwork.getNetworkService().getDeviceAlarmList( deviceId = currentDeviceId, pageNum = "1", - pageSize = "100" + pageSize = "10" ) Log.d("AlarmLogActivity", "请求完成") diff --git a/app/src/main/java/com/example/defenseapplication/login/FaceLoginActivity.kt b/app/src/main/java/com/example/defenseapplication/login/FaceLoginActivity.kt index 38f4ceb..64b92f5 100644 --- a/app/src/main/java/com/example/defenseapplication/login/FaceLoginActivity.kt +++ b/app/src/main/java/com/example/defenseapplication/login/FaceLoginActivity.kt @@ -35,9 +35,6 @@ class FaceLoginActivity : AppCompatActivity() { binding.btnStartVerification.setOnClickListener { val intent= Intent(this, FaceVerificationActivity::class.java) startActivity(intent) - Toast.makeText(this, R.string.redirect_face_recognition_page, Toast.LENGTH_SHORT).show() - - } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/defenseapplication/personal/FaceManagementActivity.kt b/app/src/main/java/com/example/defenseapplication/personal/FaceManagementActivity.kt index dcf8533..e4a60a8 100644 --- a/app/src/main/java/com/example/defenseapplication/personal/FaceManagementActivity.kt +++ b/app/src/main/java/com/example/defenseapplication/personal/FaceManagementActivity.kt @@ -2,14 +2,9 @@ package com.example.defenseapplication.personal import android.content.Intent import android.os.Bundle -import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.ViewCompat -import androidx.core.view.WindowInsetsCompat -import com.example.defenseapplication.R import com.example.defenseapplication.databinding.FaceManagementActivityBinding -import com.example.defenseapplication.databinding.LoginPasswordActivityBinding -import com.example.defenseapplication.login.FaceVerificationActivity +import com.example.defenseapplication.login.FaceLoginActivity import com.gyf.immersionbar.ImmersionBar //人脸管理页面 @@ -29,7 +24,7 @@ class FaceManagementActivity : AppCompatActivity() { finish() } binding.faceManagement.setOnClickListener { - startActivity(Intent(this, FaceVerificationActivity::class.java)) + startActivity(Intent(this, FaceLoginActivity::class.java)) } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/defenseapplication/view/FaceOverlayView.kt b/app/src/main/java/com/example/defenseapplication/view/FaceOverlayView.kt index 6bd78fc..87c2d56 100644 --- a/app/src/main/java/com/example/defenseapplication/view/FaceOverlayView.kt +++ b/app/src/main/java/com/example/defenseapplication/view/FaceOverlayView.kt @@ -1,64 +1,81 @@ package com.example.defenseapplication.view import android.content.Context -import android.graphics.Canvas -import android.graphics.Color -import android.graphics.Paint -import android.graphics.Path -import android.graphics.RectF +import android.graphics.* import android.util.AttributeSet import android.view.View import com.google.mlkit.vision.face.Face -class FaceOverlayView(context: Context, attrs: AttributeSet?) : View(context, attrs) { - private val framePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { +class FaceOverlayView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : View(context, attrs, defStyleAttr) { + + private val whitePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = Color.WHITE - style = Paint.Style.STROKE - strokeWidth = 6f - } - private val maskPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = Color.parseColor("#7A000000") style = Paint.Style.FILL } - private val facePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = Color.parseColor("#80FFFFFF") - style = Paint.Style.STROKE - strokeWidth = 3f + private val clearPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) } - private val maskPath = Path() - private val frameRect = RectF() - private var faces = mutableListOf() + private val circlePath = Path() + private var centerX = 0f + private var centerY = 0f + private var radius = 0f - fun setFaces(faces: List) { - this.faces = faces.toMutableList() - invalidate() // 触发 onDraw + // 需要绘制的所有人脸边界框(初始为空) + private var faces: List = emptyList() + + // 绘制人脸框的画笔 + private val facePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + color = Color.GREEN + style = Paint.Style.STROKE + strokeWidth = 6f + } + + override fun onSizeChanged(w: Int, h: Int, oldW: Int, oldH: Int) { + super.onSizeChanged(w, h, oldW, oldH) + // 计算圆形区域(取屏幕中心,半径为宽高中较小值的一半,留一些边距) + centerX = w / 2f + centerY = h / 2f + radius = minOf(w, h) / 2f * 0.8f + circlePath.reset() + circlePath.addCircle(centerX, centerY, radius, Path.Direction.CW) } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) - val cx = width / 2f - val cy = height * 0.45f - val radius = minOf(width, height) * 0.31f + // 1. 绘制白色背景 + canvas.drawColor(Color.WHITE) - maskPath.reset() - maskPath.addRect(0f, 0f, width.toFloat(), height.toFloat(), Path.Direction.CW) - maskPath.addCircle(cx, cy, radius, Path.Direction.CCW) - canvas.drawPath(maskPath, maskPaint) - canvas.drawCircle(cx, cy, radius, framePaint) + // 2. 裁剪出圆形区域并清除该区域像素(露出下层摄像头预览) + canvas.save() + canvas.clipPath(circlePath) + canvas.drawPaint(clearPaint) - frameRect.set(cx - radius, cy - radius, cx + radius, cy + radius) + // 3. 在圆形区域内绘制人脸框(坐标需要转换) for (face in faces) { val rect = face.boundingBox - val clippedLeft = rect.left.coerceAtLeast(frameRect.left.toInt()).toFloat() - val clippedTop = rect.top.coerceAtLeast(frameRect.top.toInt()).toFloat() - val clippedRight = rect.right.coerceAtMost(frameRect.right.toInt()).toFloat() - val clippedBottom = rect.bottom.coerceAtMost(frameRect.bottom.toInt()).toFloat() - if (clippedRight > clippedLeft && clippedBottom > clippedTop) { - canvas.drawRect(clippedLeft, clippedTop, clippedRight, clippedBottom, facePaint) - } + // 注意:rect 的坐标是基于 ImageProxy 中图像的原始尺寸和旋转的, + // 需要转换为当前 View 的坐标系。简单示例:直接绘制原始矩形(可能位置偏移较大) + // 更精确的做法:传入图像宽高和旋转,用 Matrix 映射。 + // 这里提供一个基本转换示例(假设预览视图已填充全屏,且无缩放裁剪): + canvas.drawRect(rect.left.toFloat(), rect.top.toFloat(), + rect.right.toFloat(), rect.bottom.toFloat(), facePaint) } + + canvas.restore() + } + + /** + * 由 FaceAnalyzer 调用,设置最新检测到的人脸列表 + */ + fun setFaces(faces: List) { + this.faces = faces + invalidate() // 触发重绘 } } \ No newline at end of file diff --git a/app/src/main/res/layout/face_login_activity.xml b/app/src/main/res/layout/face_login_activity.xml index c3b53c1..8ad26fa 100644 --- a/app/src/main/res/layout/face_login_activity.xml +++ b/app/src/main/res/layout/face_login_activity.xml @@ -4,7 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:background="@color/login_background" android:id="@+id/main" - android:padding="16dp" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".login.FaceLoginActivity"> @@ -12,12 +11,12 @@ + android:layout_marginStart="16dp" + android:layout_marginRight="16dp"> @@ -63,6 +63,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tvRegisterSubtitle" + android:layout_marginTop="10dp" android:paddingStart="16dp" android:paddingEnd="16dp"> + android:layout_marginStart="5dp" + app:layout_constraintStart_toEndOf="@id/safeIcon" + app:layout_constraintTop_toTopOf="@id/safeIcon" + app:layout_constraintBottom_toBottomOf="@id/safeIcon" /> + app:layout_constraintTop_toBottomOf="@id/tvInstruction"> @@ -166,6 +168,7 @@ android:layout_weight="1" android:layout_height="wrap_content"> @@ -202,6 +205,7 @@ android:layout_weight="1" android:layout_height="wrap_content"> @@ -238,6 +242,7 @@ android:layout_weight="1" android:layout_height="wrap_content"> @@ -276,7 +281,6 @@ android:layout_width="0dp" android:layout_height="40dp" android:layout_marginTop="40dp" - android:layout_marginBottom="16dp" android:layout_marginStart="25dp" android:layout_marginEnd="25dp" android:text="@string/start_verification" diff --git a/app/src/main/res/layout/face_verification_activity.xml b/app/src/main/res/layout/face_verification_activity.xml index d8908a5..6a48d8a 100644 --- a/app/src/main/res/layout/face_verification_activity.xml +++ b/app/src/main/res/layout/face_verification_activity.xml @@ -5,35 +5,39 @@ android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="@android:color/black" tools:context=".login.FaceVerificationActivity"> + android:layout_height="match_parent" + android:background="@android:color/black" /> + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintStart_toStartOf="parent" + android:layout_marginStart="16dp" + android:layout_marginRight="16dp"> @@ -43,7 +47,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/face_collection" - android:textColor="@android:color/white" android:textSize="22sp" android:textStyle="bold" app:layout_constraintBottom_toBottomOf="@id/backIcon" @@ -77,7 +80,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/face_in_circle" - android:textColor="@android:color/white" android:textSize="20sp" android:textStyle="bold" android:letterSpacing="0.03" /> @@ -92,7 +94,6 @@ android:paddingHorizontal="24dp" android:paddingTop="20dp" android:paddingBottom="28dp" - android:background="@drawable/bg_bottom_gradient" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent">