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

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import androidx.lifecycle.MutableLiveData
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.livedata.LiveDataEvent
import com.simprints.core.livedata.LiveDataEventWithContent
import com.simprints.core.livedata.send
import com.simprints.core.tools.time.Timestamp
import com.simprints.face.capture.FaceCaptureResult
import com.simprints.face.capture.models.FaceDetection
import com.simprints.face.capture.usecases.BitmapToByteArrayUseCase
import com.simprints.face.capture.usecases.IsUsingAutoCaptureUseCase
import com.simprints.face.capture.usecases.SaveFaceSampleUseCase
import com.simprints.face.capture.usecases.ShouldShowInstructionsScreenUseCase
import com.simprints.face.capture.usecases.SimpleCaptureEventReporter
Expand Down Expand Up @@ -78,9 +79,9 @@ internal class FaceCaptureViewModel @Inject constructor(
get() = _unexpectedErrorEvent
private val _unexpectedErrorEvent = MutableLiveData<LiveDataEvent>()

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

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

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

_finishFlowEvent.send(FaceCaptureResult(referenceId, items))
_finishFlowEvent.send(CaptureIdentity(referenceId, Modality.FACE, items))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.simprints.face.capture.usecases

import com.simprints.infra.config.store.models.GeneralConfiguration
import com.simprints.core.domain.common.Modality
import com.simprints.infra.events.session.SessionEventRepository
import com.simprints.infra.images.ImageRepository
import com.simprints.infra.images.model.SecuredImageRef
Expand All @@ -23,7 +23,7 @@ internal class SaveFaceSampleUseCase @Inject constructor(
return coreImageRepository.storeSample(
projectId = sessionScope.projectId,
sessionId = sessionScope.id,
modality = GeneralConfiguration.Modality.FACE,
modality = Modality.FACE,
sampleId = captureEventId,
fileExtension = "jpg",
sampleBytes = imageBytes,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.simprints.face.infra.basebiosdk.matching

import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.sample.Identity

abstract class FaceMatcher(
open val probeSamples: List<FaceSample>
open val probeSamples: List<CaptureSample>,
) : AutoCloseable {
/**
* Get highest comparison score for matching candidate template against samples
*
* @param candidate
* @return the highest comparison score
*/
abstract suspend fun getHighestComparisonScoreForCandidate(candidate: FaceIdentity): Float
abstract suspend fun getHighestComparisonScoreForCandidate(candidate: Identity): Float
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.simprints.face.infra.biosdkresolver

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

override fun matcherName(): String = "SIM_FACE"

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

import com.simprints.core.domain.sample.CaptureSample
import com.simprints.face.infra.basebiosdk.detection.FaceDetector
import com.simprints.face.infra.basebiosdk.initialization.FaceBioSdkInitializer
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
import com.simprints.face.infra.basebiosdk.matching.FaceSample

interface FaceBioSDK {
val initializer: FaceBioSdkInitializer
Expand All @@ -15,5 +15,5 @@ interface FaceBioSDK {

fun matcherName(): String

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

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

override fun matcherName(): String = "RANK_ONE"

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

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

override fun matcherName(): String = "RANK_ONE"

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

import com.simprints.core.ExcludedFromGeneratedTestCoverageReports
import com.simprints.core.domain.sample.CaptureSample
import com.simprints.face.infra.basebiosdk.detection.FaceDetector
import com.simprints.face.infra.basebiosdk.initialization.FaceBioSdkInitializer
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
import com.simprints.face.infra.basebiosdk.matching.FaceSample
import javax.inject.Inject
import javax.inject.Singleton

Expand All @@ -26,5 +26,5 @@ class SimFaceBioSdk @Inject constructor() : FaceBioSDK {

override fun matcherName(): String = TODO()

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

import com.simprints.core.ExcludedFromGeneratedTestCoverageReports
import com.simprints.core.domain.sample.CaptureSample
import com.simprints.face.infra.basebiosdk.detection.FaceDetector
import com.simprints.face.infra.basebiosdk.initialization.FaceBioSdkInitializer
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
import com.simprints.face.infra.basebiosdk.matching.FaceSample
import javax.inject.Inject
import javax.inject.Singleton

Expand All @@ -26,5 +26,5 @@ class SimFaceBioSdk @Inject constructor() : FaceBioSDK {

override fun matcherName(): String = TODO()

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

import com.google.common.truth.*
import com.simprints.biometrics.simface.SimFace
import com.simprints.face.infra.simface.detection.SimFaceDetector
import com.simprints.face.infra.simface.initialization.SimFaceInitializer
import io.mockk.*
import org.junit.Test

Expand All @@ -9,7 +12,11 @@ class SimFaceSdkTest {

@Test
fun createMatcher() {
bioSdk = SimFaceBioSdk(mockk(), mockk(), mockk(relaxed = true))
bioSdk = SimFaceBioSdk(
initializer = mockk<SimFaceInitializer>(),
detector = mockk<SimFaceDetector>(),
simFace = mockk<SimFace>(relaxed = true),
)

val matcher = bioSdk.createMatcher(emptyList())

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

import com.simprints.core.ExcludedFromGeneratedTestCoverageReports
import com.simprints.face.infra.basebiosdk.matching.FaceIdentity
import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.sample.Identity
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
import com.simprints.face.infra.basebiosdk.matching.FaceSample
import io.rankone.rocsdk.embedded.SWIGTYPE_p_unsigned_char
import io.rankone.rocsdk.embedded.roc
import io.rankone.rocsdk.embedded.rocConstants.ROC_FAST_FV_SIZE
Expand All @@ -12,26 +12,25 @@ 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<FaceSample>
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 suspend fun getHighestComparisonScoreForCandidate(candidate: FaceIdentity): Float =
probeTemplates.flatMap { probeTemplate ->
candidate.faces.map { face ->
override suspend fun getHighestComparisonScoreForCandidate(candidate: Identity): Float = probeTemplates
.flatMap { probeTemplate ->
candidate.samples.map { face ->
getSimilarityScoreForCandidate(probeTemplate, face.template)
}
}.max()

private fun getSimilarityScoreForCandidate(
probeTemplate: SWIGTYPE_p_unsigned_char,
candidateTemplate: ByteArray
candidateTemplate: ByteArray,
): Float {
val matchTemplate = roc.new_uint8_t_array(ROC_FAST_FV_SIZE.toInt())
roc.memmove(roc.roc_cast(matchTemplate), candidateTemplate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,26 @@ 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.face.infra.basebiosdk.matching.FaceIdentity
import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.sample.Identity
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
import com.simprints.face.infra.basebiosdk.matching.FaceSample

@ExcludedFromGeneratedTestCoverageReports(
reason = "This function uses roc class that has native functions and can't be mocked",
)
class RocV3Matcher(
override val probeSamples: List<FaceSample>
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 suspend fun getHighestComparisonScoreForCandidate(candidate: FaceIdentity): Float =
probeTemplates.flatMap { probeTemplate ->
candidate.faces.map { face ->
override suspend fun getHighestComparisonScoreForCandidate(candidate: Identity): Float = probeTemplates
.flatMap { probeTemplate ->
candidate.samples.map { face ->
getSimilarityScoreForCandidate(probeTemplate, face.template)
}
}.max()
Expand Down
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.face.infra.basebiosdk.matching.FaceIdentity
import com.simprints.core.domain.sample.CaptureSample
import com.simprints.core.domain.sample.Identity
import com.simprints.face.infra.basebiosdk.matching.FaceMatcher
import com.simprints.face.infra.basebiosdk.matching.FaceSample

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

override suspend fun getHighestComparisonScoreForCandidate(candidate: FaceIdentity): Float = probeTemplates
override suspend fun getHighestComparisonScoreForCandidate(candidate: Identity): Float = probeTemplates
.flatMap { probeTemplate ->
candidate.faces.map { face ->
candidate.samples.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