使用 CameraView 在 Android 上使用 ML Kit 检测人脸
Posted
技术标签:
【中文标题】使用 CameraView 在 Android 上使用 ML Kit 检测人脸【英文标题】:Detect Faces with ML Kit on Android using CameraView 【发布时间】:2019-10-12 09:40:39 【问题描述】:我正在尝试在 android 上运行此 example of face detection with the firebase MLkit。我使用库 CameraView 而不是内置的 CameraView。 运行日志中显示的代码:Faces: [],因此没有从相机中找到人脸。
您可以结帐the project here on github。
代码:
import android.os.Bundle
import android.util.Log
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
import android.widget.TextView
import androidx.annotation.WorkerThread
import com.otaliastudios.cameraview.CameraView
import com.otaliastudios.cameraview.Frame
import com.otaliastudios.cameraview.FrameProcessor
import com.otaliastudios.cameraview.Size
import androidx.core.view.ViewCompat.getRotation
import com.google.android.gms.tasks.OnFailureListener
import com.google.firebase.FirebaseApp
import com.google.firebase.ml.vision.FirebaseVision
import com.google.firebase.ml.vision.common.FirebaseVisionImage
import com.google.firebase.ml.vision.common.FirebaseVisionImageMetadata
import com.google.firebase.ml.vision.face.FirebaseVisionFace
import com.google.firebase.ml.vision.face.FirebaseVisionFaceContour
import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetectorOptions
import com.google.firebase.ml.vision.face.FirebaseVisionFaceLandmark
class MainActivity : AppCompatActivity()
private lateinit var textMessage: TextView
private lateinit var camera:CameraView
private val onNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener item ->
when (item.itemId)
R.id.navigation_home ->
textMessage.setText(R.string.title_home)
return@OnNavigationItemSelectedListener true
R.id.navigation_dashboard ->
textMessage.setText(R.string.title_dashboard)
return@OnNavigationItemSelectedListener true
R.id.navigation_notifications ->
textMessage.setText(R.string.title_notifications)
return@OnNavigationItemSelectedListener true
false
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
textMessage = findViewById(R.id.message)
navView.setOnNavigationItemSelectedListener(onNavigationItemSelectedListener)
camera = findViewById<CameraView>(R.id.camera)
camera.setLifecycleOwner(this)
val realTimeOpts1 = FirebaseVisionFaceDetectorOptions.Builder()
.setContourMode(FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS)
.build()
val realTimeOpts = FirebaseVisionFaceDetectorOptions.Builder()
.setPerformanceMode(FirebaseVisionFaceDetectorOptions.ACCURATE)
.setLandmarkMode(FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS)
.build()
FirebaseApp.initializeApp(this);
camera.addFrameProcessor frame ->
val data = frame.data
val rotation = frame.rotation
val time = frame.time
val size = frame.size
val format = frame.format
val metadata = FirebaseVisionImageMetadata.Builder()
.setWidth(480) // 480x360 is typically sufficient for
.setHeight(360) // image recognition
.setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
.setRotation(3)
.build()
val image = FirebaseVisionImage.fromByteArray(data, metadata)
val detector = FirebaseVision.getInstance()
.getVisionFaceDetector(realTimeOpts)
val result = detector.detectInImage(image)
.addOnSuccessListener faces ->
// Task completed successfully
// ...
Log.e("FACE", faces.toString())
for (face in faces)
val bounds = face.boundingBox
val rotY = face.headEulerAngleY // Head is rotated to the right rotY degrees
val rotZ = face.headEulerAngleZ // Head is tilted sideways rotZ degrees
// If landmark detection was enabled (mouth, ears, eyes, cheeks, and
// nose available):
val leftEar = face.getLandmark(FirebaseVisionFaceLandmark.LEFT_EAR)
leftEar?.let
val leftEarPos = leftEar.position
// If contour detection was enabled:
val leftEyeContour = face.getContour(FirebaseVisionFaceContour.LEFT_EYE).points
val upperLipBottomContour = face.getContour(FirebaseVisionFaceContour.UPPER_LIP_BOTTOM).points
// If classification was enabled:
if (face.smilingProbability != FirebaseVisionFace.UNCOMPUTED_PROBABILITY)
val smileProb = face.smilingProbability
if (face.rightEyeOpenProbability != FirebaseVisionFace.UNCOMPUTED_PROBABILITY)
val rightEyeOpenProb = face.rightEyeOpenProbability
// If face tracking was enabled:
if (face.trackingId != FirebaseVisionFace.INVALID_ID)
val id = face.trackingId
.addOnFailureListener(
object : OnFailureListener
override fun onFailure(e: Exception)
// Task failed with an exception
// ...
Log.e("M", e.toString())
)
在activity_main.xml中:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_
android:layout_
tools:context=".MainActivity">
<TextView
android:id="@+id/message"
android:layout_
android:layout_
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:text="@string/title_home"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.cardview.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_gravity="center"
android:layout_
card_view:cardCornerRadius="280dp"
android:layout_>
<com.otaliastudios.cameraview.CameraView
android:id="@+id/camera"
app:cameraFacing="front"
android:keepScreenOn="true"
android:layout_
android:layout_ />
</androidx.cardview.widget.CardView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_
android:layout_
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
对Fotoapparat 也进行了同样的尝试,结果相同:未找到面孔。我在这里错过了什么?
【问题讨论】:
【参考方案1】:尝试以编程方式从frame
获取高度和宽度,而不是硬编码。
【讨论】:
【参考方案2】:我认为问题在于 frame.rotation 值。也许您可以将 FirebaseVisionImageMetadata.ROTATION_90 用于 FirebaseVisionImageMetadata
【讨论】:
以上是关于使用 CameraView 在 Android 上使用 ML Kit 检测人脸的主要内容,如果未能解决你的问题,请参考以下文章
为android构建应用程序时用于cameraview的多个文件反应本机
Android ViewPager,片段中的cameraview未显示