Last active
December 30, 2024 05:35
-
-
Save iamjosephmj/cd58862c466189644f59945881db8361 to your computer and use it in GitHub Desktop.
Face Landmarker centering logic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
android:id="@+id/camera_container" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent"> | |
<androidx.camera.view.PreviewView | |
android:id="@+id/view_finder" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" // removed app:scaleType="fillStart" | |
/> | |
.... | |
</androidx.coordinatorlayout.widget.CoordinatorLayout> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
override fun draw(canvas: Canvas) { | |
super.draw(canvas) | |
// Clear previous drawings if results exist but have no face landmarks | |
if (results?.faceLandmarks().isNullOrEmpty()) { | |
clear() | |
return | |
} | |
results?.let { faceLandmarkerResult -> | |
// Calculate scaled image dimensions | |
val scaledImageWidth = imageWidth * scaleFactor | |
val scaledImageHeight = imageHeight * scaleFactor | |
// Calculate offsets to center the image on the canvas | |
val offsetX = (width - scaledImageWidth) / 2f | |
val offsetY = (height - scaledImageHeight) / 2f | |
// Iterate through each detected face | |
faceLandmarkerResult.faceLandmarks().forEach { faceLandmarks -> | |
// Draw all landmarks for the current face | |
drawFaceLandmarks(canvas, faceLandmarks, offsetX, offsetY) | |
// Draw all connectors for the current face | |
drawFaceConnectors(canvas, faceLandmarks, offsetX, offsetY) | |
} | |
} | |
} | |
/** | |
* Draws all landmarks for a single face on the canvas. | |
*/ | |
private fun drawFaceLandmarks( | |
canvas: Canvas, | |
faceLandmarks: List<NormalizedLandmark>, | |
offsetX: Float, | |
offsetY: Float | |
) { | |
faceLandmarks.forEach { landmark -> | |
val x = landmark.x() * imageWidth * scaleFactor + offsetX | |
val y = landmark.y() * imageHeight * scaleFactor + offsetY | |
canvas.drawPoint(x, y, pointPaint) | |
} | |
} | |
/** | |
* Draws all connectors between landmarks for a single face on the canvas. | |
*/ | |
private fun drawFaceConnectors( | |
canvas: Canvas, | |
faceLandmarks: List<NormalizedLandmark>, | |
offsetX: Float, | |
offsetY: Float | |
) { | |
FaceLandmarker.FACE_LANDMARKS_CONNECTORS.filterNotNull().forEach { connector -> | |
val startLandmark = faceLandmarks.getOrNull(connector.start()) | |
val endLandmark = faceLandmarks.getOrNull(connector.end()) | |
if (startLandmark != null && endLandmark != null) { | |
val startX = startLandmark.x() * imageWidth * scaleFactor + offsetX | |
val startY = startLandmark.y() * imageHeight * scaleFactor + offsetY | |
val endX = endLandmark.x() * imageWidth * scaleFactor + offsetX | |
val endY = endLandmark.y() * imageHeight * scaleFactor + offsetY | |
canvas.drawLine(startX, startY, endX, endY, linePaint) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment