google-ai-edge / mediapipe-samples

Apache License 2.0
1.48k stars 381 forks source link

Showing only certain landmarks on android FaceLandmarker App #372

Open connormeaton opened 4 months ago

connormeaton commented 4 months ago

Hello, I am playing around with your Face Landmarker app for android.

I am very inexperienced with Koltin, so my apologies. I would like to display only certain landmarks on the face when running the app and I'm not sure where to start. For example, if I only wanted to show the left eye landmarks on the app, how would I do that?

In python, I would find the variable storing the facelandmark coordinates, and I would index it by these values to get the left eyelandmarks: [85, 246, 161, 160, 159, 158, 157, 173, 155, 154, 153, 145, 144, 163]. How would I do that in this koltin project? What variable contains the landmarks and how would I index it like this?

It looks like OverlayView.kt setResults function might be the place to start, but I'm really not sure. Any advise would be helpful. Thank you!

https://github.com/googlesamples/mediapipe/tree/main/examples/face_landmarker/android

PaulTR commented 4 months ago

Yup the OverlayView setResults function is where the landmarks to display are set! :) You can add a filter before sending those results to limit it to only the landmarks that you want.

connormeaton commented 4 months ago

Thank you for your reply. That is really helpful. Can you critique this specific section? My approach is to modify setResults() to:

fun setResults(
        faceLandmarkerResults: FaceLandmarkerResult,
        imageHeight: Int,
        imageWidth: Int,
        runningMode: RunningMode = RunningMode.IMAGE
    ) {
        results = faceLandmarkerResults
        val indexList = listOf(85, 246, 161, 160, 159, 158, 157, 173, 155, 154, 153, 145, 144, 163)
        val filteredNumbers = results.filterIndexed { index, value ->
            index in indexList
        }
        results = filteredNumbers
        this.imageHeight = imageHeight
        this.imageWidth = imageWidth

        scaleFactor = when (runningMode) {
            RunningMode.IMAGE,
            RunningMode.VIDEO -> {
                min(width * 1f / imageWidth, height * 1f / imageHeight)
            }
            RunningMode.LIVE_STREAM -> {
                // PreviewView is in FILL_START mode. So we need to scale up the
                // landmarks to match with the size that the captured images will be
                // displayed.
                max(width * 1f / imageWidth, height * 1f / imageHeight)
            }
        }
        invalidate()
    }

However, I keep getting the error that the code cannot infer the type for this parameter (point to index and value). How should can I properly type these parameters, or, is there another way I should do this?

Thank you!

The full error is below.

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public inline fun <T> Array<out TypeVariable(T)>.filterIndexed(predicate: (index: Int, TypeVariable(T)) -> Boolean): List<TypeVariable(T)> defined in kotlin.collections
public inline fun BooleanArray.filterIndexed(predicate: (index: Int, Boolean) -> Boolean): List<Boolean> defined in kotlin.collections
public inline fun ByteArray.filterIndexed(predicate: (index: Int, Byte) -> Boolean): List<Byte> defined in kotlin.collections
public inline fun CharArray.filterIndexed(predicate: (index: Int, Char) -> Boolean): List<Char> defined in kotlin.collections
public inline fun CharSequence.filterIndexed(predicate: (index: Int, Char) -> Boolean): CharSequence defined in kotlin.text
public inline fun DoubleArray.filterIndexed(predicate: (index: Int, Double) -> Boolean): List<Double> defined in kotlin.collections
public inline fun FloatArray.filterIndexed(predicate: (index: Int, Float) -> Boolean): List<Float> defined in kotlin.collections
public inline fun IntArray.filterIndexed(predicate: (index: Int, Int) -> Boolean): List<Int> defined in kotlin.collections
public inline fun LongArray.filterIndexed(predicate: (index: Int, Long) -> Boolean): List<Long> defined in kotlin.collections
public inline fun ShortArray.filterIndexed(predicate: (index: Int, Short) -> Boolean): List<Short> defined in kotlin.collections
public inline fun String.filterIndexed(predicate: (index: Int, Char) -> Boolean): String defined in kotlin.text
public inline fun UByteArray.filterIndexed(predicate: (index: Int, UByte) -> Boolean): List<UByte> defined in kotlin.collections
public inline fun UIntArray.filterIndexed(predicate: (index: Int, UInt) -> Boolean): List<UInt> defined in kotlin.collections
public inline fun ULongArray.filterIndexed(predicate: (index: Int, ULong) -> Boolean): List<ULong> defined in kotlin.collections
public inline fun UShortArray.filterIndexed(predicate: (index: Int, UShort) -> Boolean): List<UShort> defined in kotlin.collections
public inline fun <T> Iterable<TypeVariable(T)>.filterIndexed(predicate: (index: Int, TypeVariable(T)) -> Boolean): List<TypeVariable(T)> defined in kotlin.collections
public fun <T> Sequence<TypeVariable(T)>.filterIndexed(predicate: (index: Int, TypeVariable(T)) -> Boolean): Sequence<TypeVariable(T)> defined in kotlin.sequences