Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.simprints.core.DeviceID
import com.simprints.core.domain.common.Modality
import com.simprints.core.domain.sample.CaptureIdentity
import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.capture.BiometricReferenceCapture
import com.simprints.core.domain.capture.BiometricTemplateCapture
import com.simprints.core.livedata.LiveDataEvent
import com.simprints.core.livedata.LiveDataEventWithContent
import com.simprints.core.livedata.send
Expand Down Expand Up @@ -79,9 +79,9 @@ internal class FaceCaptureViewModel @Inject constructor(
get() = _unexpectedErrorEvent
private val _unexpectedErrorEvent = MutableLiveData<LiveDataEvent>()

val finishFlowEvent: LiveData<LiveDataEventWithContent<CaptureIdentity>>
val finishFlowEvent: LiveData<LiveDataEventWithContent<BiometricReferenceCapture>>
get() = _finishFlowEvent
private val _finishFlowEvent = MutableLiveData<LiveDataEventWithContent<CaptureIdentity>>()
private val _finishFlowEvent = MutableLiveData<LiveDataEventWithContent<BiometricReferenceCapture>>()

val invalidLicense: LiveData<LiveDataEvent>
get() = _invalidLicense
Expand Down Expand Up @@ -179,18 +179,21 @@ internal class FaceCaptureViewModel @Inject constructor(
saveFaceDetections()
}

val items = faceDetections.mapIndexed { index, detection ->
CaptureSample(
val items = faceDetections.map { detection ->
BiometricTemplateCapture(
captureEventId = detection.id,
template = detection.face?.template ?: ByteArray(0),
format = detection.face?.format ?: "",
modality = Modality.FACE,
)
}
val referenceId = UUID.randomUUID().toString()
eventReporter.addBiometricReferenceCreationEvents(referenceId, items.map { it.captureEventId })

_finishFlowEvent.send(CaptureIdentity(referenceId, Modality.FACE, items))
val format = faceDetections
.firstOrNull()
?.face
?.format
.orEmpty()
_finishFlowEvent.send(BiometricReferenceCapture(referenceId, Modality.FACE, format, items))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package com.simprints.face.infra.basebiosdk.matching

import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.sample.Identity
import com.simprints.core.domain.capture.BiometricReferenceCapture
import com.simprints.core.domain.reference.CandidateRecord

abstract class FaceMatcher(
open val probeSamples: List<CaptureSample>,
open val probeReference: BiometricReferenceCapture,
) : AutoCloseable {
/**
* Get highest comparison score for matching candidate template against samples
*
* @param candidate
* @return the highest comparison score
*/
abstract suspend fun getHighestComparisonScoreForCandidate(candidate: Identity): Float
abstract suspend fun getHighestComparisonScoreForCandidate(candidate: CandidateRecord): Float
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.simprints.face.infra.biosdkresolver

import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.capture.BiometricReferenceCapture
import com.simprints.face.infra.basebiosdk.detection.FaceDetector
import com.simprints.face.infra.basebiosdk.initialization.FaceBioSdkInitializer
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
Expand All @@ -15,5 +15,5 @@ interface FaceBioSDK {

fun matcherName(): String

fun createMatcher(probeSamples: List<CaptureSample>): FaceMatcher
fun createMatcher(probeReference: BiometricReferenceCapture): FaceMatcher
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.simprints.face.infra.biosdkresolver

import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.capture.BiometricReferenceCapture
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
import com.simprints.face.infra.rocv1.detection.RocV1Detector
import com.simprints.face.infra.rocv1.detection.RocV1Detector.Companion.RANK_ONE_TEMPLATE_FORMAT_1_23
Expand All @@ -20,5 +20,5 @@ class RocV1BioSdk @Inject constructor(

override fun matcherName(): String = "RANK_ONE"

override fun createMatcher(probeSamples: List<CaptureSample>): FaceMatcher = RocV1Matcher(probeSamples)
override fun createMatcher(probeReference: BiometricReferenceCapture): FaceMatcher = RocV1Matcher(probeReference)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.simprints.face.infra.biosdkresolver

import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.capture.BiometricReferenceCapture
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
import com.simprints.face.infra.rocv3.detection.RocV3Detector
import com.simprints.face.infra.rocv3.detection.RocV3Detector.Companion.RANK_ONE_TEMPLATE_FORMAT_3_1
Expand All @@ -20,5 +20,5 @@ class RocV3BioSdk @Inject constructor(

override fun matcherName(): String = "RANK_ONE"

override fun createMatcher(probeSamples: List<CaptureSample>): FaceMatcher = RocV3Matcher(probeSamples)
override fun createMatcher(probeReference: BiometricReferenceCapture): FaceMatcher = RocV3Matcher(probeReference)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.simprints.face.infra.biosdkresolver

import com.simprints.biometrics.simface.SimFace
import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.capture.BiometricReferenceCapture
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
import com.simprints.face.infra.simface.detection.SimFaceDetector
import com.simprints.face.infra.simface.initialization.SimFaceInitializer
Expand All @@ -21,5 +21,5 @@ class SimFaceBioSdk @Inject constructor(

override fun matcherName(): String = "SIM_FACE"

override fun createMatcher(probeSamples: List<CaptureSample>): FaceMatcher = SimFaceMatcher(simFace, probeSamples)
override fun createMatcher(probeReference: BiometricReferenceCapture): FaceMatcher = SimFaceMatcher(simFace, probeReference)
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
package com.simprints.face.infra.biosdkresolver


import com.google.common.truth.Truth.*
import io.mockk.*
import org.junit.Test

class RocV1BioSdkTest {


private lateinit var rocV1BioSdk: RocV1BioSdk

@Test
fun createMatcher() {
rocV1BioSdk = RocV1BioSdk(mockk(), mockk())

val matcher = rocV1BioSdk.createMatcher(emptyList())
val matcher = rocV1BioSdk.createMatcher(
mockk { every { templates } returns emptyList() },
)

assertThat(matcher).isNotNull()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ class RocV3BioSdkTest {
fun createMatcher() {
rocV3BioSdk = RocV3BioSdk(mockk(), mockk())

val matcher = rocV3BioSdk.createMatcher(emptyList())
val matcher = rocV3BioSdk.createMatcher(
mockk { every { templates } returns emptyList() },
)

assertThat(matcher).isNotNull()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class SimFaceSdkTest {
simFace = mockk<SimFace>(relaxed = true),
)

val matcher = bioSdk.createMatcher(emptyList())
val matcher = bioSdk.createMatcher(mockk())

Truth.assertThat(matcher).isNotNull()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.simprints.face.infra.rocv1.matching

import com.simprints.core.ExcludedFromGeneratedTestCoverageReports
import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.sample.Identity
import com.simprints.core.domain.capture.BiometricReferenceCapture
import com.simprints.core.domain.reference.CandidateRecord
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
import io.rankone.rocsdk.embedded.SWIGTYPE_p_unsigned_char
import io.rankone.rocsdk.embedded.roc
Expand All @@ -12,18 +12,19 @@ import io.rankone.rocsdk.embedded.rocConstants.ROC_FAST_FV_SIZE
reason = "This function uses roc class that has native functions and can't be mocked",
)
class RocV1Matcher(
override val probeSamples: List<CaptureSample>,
) : FaceMatcher(probeSamples) {
var probeTemplates: List<SWIGTYPE_p_unsigned_char> = probeSamples.mapIndexed { i, probe ->
val probeTemplate: SWIGTYPE_p_unsigned_char =
roc.new_uint8_t_array(ROC_FAST_FV_SIZE.toInt())
roc.memmove(roc.roc_cast(probeTemplate), probe.template)
probeTemplate
}
override val probeReference: BiometricReferenceCapture,
) : FaceMatcher(probeReference) {
var nativeProbeTemplates: List<SWIGTYPE_p_unsigned_char> = probeReference.templates
.map { it.template }
.map { probe ->
val probeTemplate: SWIGTYPE_p_unsigned_char = roc.new_uint8_t_array(ROC_FAST_FV_SIZE.toInt())
roc.memmove(roc.roc_cast(probeTemplate), probe)
probeTemplate
}

override suspend fun getHighestComparisonScoreForCandidate(candidate: Identity): Float = probeTemplates
override suspend fun getHighestComparisonScoreForCandidate(candidate: CandidateRecord): Float = nativeProbeTemplates
.flatMap { probeTemplate ->
candidate.samples.map { face ->
candidate.references.flatMap { it.templates }.map { face ->
getSimilarityScoreForCandidate(probeTemplate, face.template)
}
}.max()
Expand All @@ -47,6 +48,6 @@ class RocV1Matcher(
}

override fun close() {
probeTemplates.forEach { roc.delete_uint8_t_array(it) }
nativeProbeTemplates.forEach { roc.delete_uint8_t_array(it) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package com.simprints.infra.rocwrapper.matching

import com.google.common.truth.*
import com.simprints.face.infra.rocv1.matching.RocV1Matcher
import io.mockk.every
import io.mockk.mockk
import org.junit.Test

class RocV1MatcherTest {
// Dummy test to generate jacoco reports.
@Test
fun getMatcherName() {
Truth.assertThat(RocV1Matcher(emptyList())).isNotNull()
Truth.assertThat(RocV1Matcher(mockk { every { templates } returns emptyList() })).isNotNull()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,27 @@ import ai.roc.rocsdk.embedded.SWIGTYPE_p_unsigned_char
import ai.roc.rocsdk.embedded.roc
import ai.roc.rocsdk.embedded.rocConstants.ROC_FACE_FAST_FV_SIZE
import com.simprints.core.ExcludedFromGeneratedTestCoverageReports
import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.sample.Identity
import com.simprints.core.domain.capture.BiometricReferenceCapture
import com.simprints.core.domain.reference.CandidateRecord
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher

@ExcludedFromGeneratedTestCoverageReports(
reason = "This function uses roc class that has native functions and can't be mocked",
)
class RocV3Matcher(
override val probeSamples: List<CaptureSample>,
) : FaceMatcher(probeSamples) {
var probeTemplates: List<SWIGTYPE_p_unsigned_char> = probeSamples.mapIndexed { i, probe ->
val probeTemplate: SWIGTYPE_p_unsigned_char =
roc.new_uint8_t_array(ROC_FACE_FAST_FV_SIZE.toInt())
roc.memmove(roc.roc_cast(probeTemplate), probe.template)
probeTemplate
}
override val probeReference: BiometricReferenceCapture,
) : FaceMatcher(probeReference) {
var nativeProbeTemplates: List<SWIGTYPE_p_unsigned_char> = probeReference.templates
.map { it.template }
.map { probe ->
val probeTemplate: SWIGTYPE_p_unsigned_char = roc.new_uint8_t_array(ROC_FACE_FAST_FV_SIZE.toInt())
roc.memmove(roc.roc_cast(probeTemplate), probe)
probeTemplate
}

override suspend fun getHighestComparisonScoreForCandidate(candidate: Identity): Float = probeTemplates
override suspend fun getHighestComparisonScoreForCandidate(candidate: CandidateRecord): Float = nativeProbeTemplates
.flatMap { probeTemplate ->
candidate.samples.map { face ->
candidate.references.flatMap { it.templates }.map { face ->
getSimilarityScoreForCandidate(probeTemplate, face.template)
}
}.max()
Expand All @@ -47,6 +48,6 @@ class RocV3Matcher(
}

override fun close() {
probeTemplates.forEach { roc.delete_uint8_t_array(it) }
nativeProbeTemplates.forEach { roc.delete_uint8_t_array(it) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package com.simprints.infra.rocwrapper.matching

import com.google.common.truth.Truth
import com.simprints.face.infra.rocv3.matching.RocV3Matcher
import io.mockk.every
import io.mockk.mockk
import org.junit.Test

// Dummy test to generate jacoco reports.
class RocV3MatcherTest {
@Test
fun getMatcherName() {
Truth.assertThat(RocV3Matcher(emptyList())).isNotNull()
Truth.assertThat(RocV3Matcher(mockk { every { templates } returns emptyList() })).isNotNull()
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package com.simprints.face.infra.simface.matching

import com.simprints.biometrics.simface.SimFace
import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.sample.Identity
import com.simprints.core.domain.capture.BiometricReferenceCapture
import com.simprints.core.domain.reference.CandidateRecord
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher

class SimFaceMatcher(
private val simFace: SimFace,
override val probeSamples: List<CaptureSample>,
) : FaceMatcher(probeSamples) {
private val probeTemplates = probeSamples.map { it.template }

override suspend fun getHighestComparisonScoreForCandidate(candidate: Identity): Float = probeTemplates
override val probeReference: BiometricReferenceCapture,
) : FaceMatcher(probeReference) {
override suspend fun getHighestComparisonScoreForCandidate(candidate: CandidateRecord): Float = probeReference
.templates
.map { it.template }
.flatMap { probeTemplate ->
candidate.samples.map { face ->
candidate.references.flatMap { it.templates }.map { face ->
val baseScore = simFace.verificationScore(probeTemplate, face.template)
// TODO: remove the adjustment after we find out why the returned range is biased towards [0.5;1]
(baseScore - 0.5).coerceAtLeast(0.0).toFloat() * 200f
Expand Down
Loading