人脸识别优化

This commit is contained in:
2026-06-01 11:38:32 +08:00
parent 5cda6d959e
commit c4fd35bfe4
6 changed files with 91 additions and 77 deletions

View File

@@ -216,7 +216,7 @@ class AlarmLogActivity : AppCompatActivity() {
val response = RetrofitNetwork.getNetworkService().getDeviceAlarmList(
deviceId = currentDeviceId,
pageNum = "1",
pageSize = "100"
pageSize = "10"
)
Log.d("AlarmLogActivity", "请求完成")

View File

@@ -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()
}
}
}

View File

@@ -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))
}
}
}

View File

@@ -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<Face>()
private val circlePath = Path()
private var centerX = 0f
private var centerY = 0f
private var radius = 0f
fun setFaces(faces: List<Face>) {
this.faces = faces.toMutableList()
invalidate() // 触发 onDraw
// 需要绘制的所有人脸边界框(初始为空)
private var faces: List<Face> = 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<Face>) {
this.faces = faces
invalidate() // 触发重绘
}
}