Advertisement

Responsive Advertisement

Face Detection Code with CameraX jetpack library

Step 0:-  add dependencies this

implementation "androidx.camera:camera-core:1.6.1"
implementation "androidx.camera:camera-camera2:1.6.1"
implementation "androidx.camera:camera-lifecycle:1.6.1"
implementation "androidx.camera:camera-view:1.6.1"

implementation 'com.google.mlkit:face-detection:16.1.7' 


Step 1 :-



import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View

class FaceOverlayView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {

// FACE VALID OR NOT
var isFaceValid = false
set(value) {
field = value
invalidate()
}

private val borderPaint = Paint().apply {

style = Paint.Style.STROKE
strokeWidth = 8f
isAntiAlias = true
}

private val overlayPaint = Paint().apply {

color = Color.parseColor("#88000000")
}

val faceRect = RectF()

override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)

val overlay =
Path().apply {

addRect(
0f,
0f,
width.toFloat(),
height.toFloat(),
Path.Direction.CW
)
}

val ovalWidth =
width * 0.65f

val ovalHeight =
height * 0.45f

val left =
(width - ovalWidth) / 2

val top =
(height - ovalHeight) / 2

val right =
left + ovalWidth

val bottom =
top + ovalHeight

faceRect.set(
left,
top,
right,
bottom
)

overlay.addOval(
faceRect,
Path.Direction.CCW
)

// DARK BACKGROUND
canvas.drawPath(
overlay,
overlayPaint
)

// BORDER COLOR
borderPaint.color =
if (isFaceValid) {
Color.GREEN
} else {
Color.WHITE
}

// DRAW OVAL
canvas.drawOval(
faceRect,
borderPaint
)
}
}


Step 2:-
xml will be like this

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout
android:id="@+id/main"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

<com.lifealchemy.yuvaap.utils.FaceOverlayView
android:id="@+id/faceOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"/>



<TextView
android:id="@+id/tvFace"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No Face"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="@android:color/white"
android:layout_margin="20dp"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:gravity="center"
android:orientation="horizontal"
android:padding="20dp">

<Button
android:id="@+id/btnSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Switch"/>

<Button
android:id="@+id/btnCapture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Capture"
android:layout_marginStart="20dp"/>

</LinearLayout>

</FrameLayout>


Step 3:- camera activity

package com.lifealchemy.yuvaap.ui.test

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.OptIn
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.core.ExperimentalGetImage
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.ImageProxy
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.google.mlkit.vision.common.InputImage
import com.google.mlkit.vision.face.FaceDetection
import com.google.mlkit.vision.face.FaceDetectorOptions
import com.lifealchemy.yuvaap.R
import com.lifealchemy.yuvaap.databinding.ActivityCameraFeatureBinding
import java.io.File

class CameraFeatureActivity : AppCompatActivity() {

private lateinit var binding:
ActivityCameraFeatureBinding

private lateinit var imageCapture:
ImageCapture

private var cameraSelector =
CameraSelector.DEFAULT_FRONT_CAMERA

// FACE DETECTOR
private val detector by lazy {

val options =
FaceDetectorOptions.Builder()
.setPerformanceMode(
FaceDetectorOptions.PERFORMANCE_MODE_FAST
)
.enableTracking()
.build()

FaceDetection.getClient(options)
}

// PERMISSION
private val cameraPermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->

if (isGranted) {

startCamera()

} else {

Toast.makeText(
this,
"Camera Permission Denied",
Toast.LENGTH_SHORT
).show()
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

enableEdgeToEdge()

binding =
ActivityCameraFeatureBinding.inflate(layoutInflater)

setContentView(binding.root)

ViewCompat.setOnApplyWindowInsetsListener(
findViewById(R.id.main)
) { v, insets ->

val systemBars =
insets.getInsets(
WindowInsetsCompat.Type.systemBars()
)

v.setPadding(
systemBars.left,
systemBars.top,
systemBars.right,
systemBars.bottom
)

insets
}

requestPermission()

initListeners()
}

// START CAMERA
private fun startCamera() {

val cameraProviderFuture =
ProcessCameraProvider.getInstance(this)

cameraProviderFuture.addListener({

val cameraProvider =
cameraProviderFuture.get()

// PREVIEW
val preview =
Preview.Builder().build()

preview.surfaceProvider =
binding.previewView.surfaceProvider

// IMAGE CAPTURE
imageCapture =
ImageCapture.Builder().build()

// ANALYSIS
val imageAnalysis =
ImageAnalysis.Builder()
.setBackpressureStrategy(
ImageAnalysis
.STRATEGY_KEEP_ONLY_LATEST
)
.build()

imageAnalysis.setAnalyzer(
ContextCompat.getMainExecutor(this)
) { imageProxy ->

detectFace(imageProxy)
}

try {

cameraProvider.unbindAll()

cameraProvider.bindToLifecycle(
this,
cameraSelector,
preview,
imageCapture,
imageAnalysis
)

} catch (e: Exception) {

e.printStackTrace()
}

}, ContextCompat.getMainExecutor(this))
}

// FACE DETECTION
@OptIn(ExperimentalGetImage::class)
private fun detectFace(
imageProxy: ImageProxy
) {

val mediaImage =
imageProxy.image

if (mediaImage == null) {

imageProxy.close()
return
}

val image =
InputImage.fromMediaImage(
mediaImage,
imageProxy.imageInfo.rotationDegrees
)

detector.process(image)

.addOnSuccessListener { faces ->

if (faces.isNotEmpty()) {

val face =
faces[0]

val box =
face.boundingBox

val centerX =
box.centerX()

val centerY =
box.centerY()

val faceWidth =
box.width()

val imageWidth =
image.width

val imageHeight =
image.height

// CENTER CHECK
val isCenter =
centerX > imageWidth * 0.20 &&
centerX < imageWidth * 0.80 &&
centerY > imageHeight * 0.15 &&
centerY < imageHeight * 0.85

// SIZE CHECK
val isBigEnough =
faceWidth > imageWidth * 0.15
val isFaceValid =
isCenter && isBigEnough
binding.faceOverlay.isFaceValid =
isFaceValid
if (
isFaceValid
) {

binding.tvFace.text =
"Face Inside Frame 😄"

} else {

binding.tvFace.text =
"Align Face Properly"
}

} else {

binding.tvFace.text =
"No Face"
}
}

.addOnFailureListener {

it.printStackTrace()
}

.addOnCompleteListener {

// IMPORTANT
imageProxy.close()
}
}

// CAMERA PERMISSION
private fun requestPermission() {

if (
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED
) {

startCamera()

} else {

cameraPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}

// CAPTURE PHOTO
private fun capturePhoto() {

val photoFile = File(
externalMediaDirs.first(),
"${System.currentTimeMillis()}.jpg"
)

val outputOptions =
ImageCapture.OutputFileOptions.Builder(photoFile)
.build()

imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(this),

object : ImageCapture.OnImageSavedCallback {

override fun onImageSaved(
outputFileResults:
ImageCapture.OutputFileResults
) {

Toast.makeText(
this@CameraFeatureActivity,
"Photo Saved",
Toast.LENGTH_SHORT
).show()
}

override fun onError(
exception: ImageCaptureException
) {

exception.printStackTrace()
}
}
)
}

// SWITCH CAMERA
private fun switchCamera() {

cameraSelector =
if (
cameraSelector ==
CameraSelector.DEFAULT_BACK_CAMERA
) {

CameraSelector.DEFAULT_FRONT_CAMERA

} else {

CameraSelector.DEFAULT_BACK_CAMERA
}

startCamera()
}

private fun initListeners() {

binding.btnCapture.setOnClickListener {

capturePhoto()
}

binding.btnSwitch.setOnClickListener {

switchCamera()
}
}

override fun onDestroy() {
super.onDestroy()

detector.close()
}
}


Post a Comment

0 Comments