DOT Android Face 8.0.0

This guide describes how to migrate DOT Android Face version 7.x to version 8.0. Only the most important changes are highlighted in this guide. For more details, see the Android Samples.

Migration Steps

Face Detector component (FaceDetector)

  • FaceDetector.detect() method now returns list of FaceDetector.Face data classes instead of list of DetectedFace interfaces.
  • Use query: FaceDetectionQuery argument of the FaceDetector.detect() method in order to specify desired detection data.

Before

val faceDetector = FaceDetectorFactory.create()
val faceImage = FaceImageFactory.create(bgrRawImage, minFaceSizeRatio, maxFaceSizeRatio)
val detectedFaces = faceDetector.detect(
  faceImage = faceImage,
  maximumFaces = 1,
)
val detectedFace = detectedFaces.first()
val confidence = detectedFace.getConfidence()
val template = detectedFace.createTemplate()
val fullFrontalImage = detectedFace.createFullFrontalImage()
val faceAspects = detectedFace.evaluateFaceAspects()
val faceQualityQuery = FaceQualityQuery(
  imageQuality = FaceImageQualityQuery(
    isSharpness = true,
  )
)
val faceQuality = detectedFace.evaluateFaceQuality(faceQualityQuery)
val passiveLiveness = detectedFace.evaluatePassiveLiveness()

After

val faceDetector = FaceDetectorFactory.create()
val faces = faceDetector.detect(
  faceImage = FaceImage(bgrRawImage, faceSizeRatioInterval),
  query = FaceDetectionQuery(
    faceQuality = FaceQualityQuery(
      imageQuality = FaceImageQualityQuery(
        evaluateSharpness = true,
      ),
    ),
    evaluatePassiveLiveness = true,
    createFullFrontalImage = true,
    createTemplate = true,
  ),
  limit = 1,
)
val face = faces.first()
val confidence = face.confidence
val faceAspects = face.faceAspects
val faceQuality = face.faceQuality
val passiveLivenessFaceAttribute = face.passiveLivenessFaceAttribute
val fullFrontalBgrRawImage = face.fullFrontalBgrRawImage
val template = face.template

All UI components use a query in their configurations

  • Use query: FaceDetectionQuery argument of the *Fragment.Configuration data class in order to specify desired detection data of the result.

Before

// Example of a subclass of FaceAutoCaptureFragment
override fun onCaptured(result: FaceAutoCaptureResult) {
  val detectedFace = result.detectedFace!!
  val confidence = detectedFace.getConfidence()
  val template = detectedFace.createTemplate()
  val fullFrontalImage = detectedFace.createFullFrontalImage()
  val faceAspects = detectedFace.evaluateFaceAspects()
  val faceQualityQuery = FaceQualityQuery(
    imageQuality = FaceImageQualityQuery(
      isSharpness = true,
    ),
  )
  val faceQuality = detectedFace.evaluateFaceQuality(faceQualityQuery)
  val passiveLiveness = detectedFace.evaluatePassiveLiveness()
}

After

// Example of a subclass of FaceAutoCaptureFragment
override fun provideConfiguration() = FaceAutoCaptureFragment.Configuration(
    query = FaceDetectionQuery(
      faceQuality = FaceQualityQuery(
        imageQuality = FaceImageQualityQuery(
          evaluateSharpness = true,
        ),
      ),
      evaluatePassiveLiveness = true,
      createFullFrontalImage = true,
      createTemplate = true,
    ),
  )

override fun onCaptured(result: FaceAutoCaptureResult) {
  val face = result.face
  val confidence = face.confidence
  val faceAspects = face.faceAspects
  val faceQuality = face.faceQuality
  val passiveLivenessFaceAttribute = face.passiveLivenessFaceAttribute
  val fullFrontalBgrRawImage = face.fullFrontalBgrRawImage
  val template = face.template
}

Eye Gaze Liveness UI component (EyeGazeLivenessFragment)

  • Replace usage of EyeGazeLivenessFragment. More details are in the integration manual and the API reference. The following points are the minimum changes required in order to migrate to version 8.0.0.
  • Add callback EyeGazeLivenessFragment.onProcessed().
  • Add callback EyeGazeLivenessFragment.onCriticalFacePresenceLost(). Before the component started again after the face presence was lost. Since version 8.0.0 there is an option to handle this kind of event via this callback. E.g. you can start over (as prior to version 8.0.0) by calling eyeGazeLivenessFragment.start() method.
  • Replace EyeGazeLivenessFragment.onFinished() with EyeGazeLivenessFragment.onFinished(). The new callback returns a new data class EyeGazeLivenessResult. Score of the liveness check is present in the EyeGazeLivenessResult only if this feature is enabled by the license. The score is null otherwise.
  • Replace EyeGazeLivenessFragment.onNoMoreSegments() with EyeGazeLivenessFragment.onAllCornersUsed().
  • Remove callback EyeGazeLivenessFragment.onStateChanged(). Since version 8.0.0 there is a new callback EyeGazeLivenessFragment.onProcessed() for handling the current state of the process.
  • Remove callback EyeGazeLivenessFragment.onEyesNotDetected(). Callback EyeGazeLivenessFragment.onCriticalFacePresenceLost() is used for this event (eyes are not clearly visible in the first corner).
  • Remove callback EyeGazeLivenessFragment.onFaceTrackingFailed(). This callback was not used in real use cases.

Before

override fun onStateChanged(eyeGazeLivenessState: EyeGazeLivenessState) {
  // Handle callback
}

override fun onFinished(score: Float, segmentImages: List<SegmentImage>) {
  // Handle callback
}

override fun onNoMoreSegments() {
  // Handle callback
}

override fun onEyesNotDetected() {
  // Handle callback
}

override fun onFaceTrackingFailed() {
  // Handle callback
}

After

override fun onProcessed(detection: FaceAutoCaptureDetection) {
  // Handle callback
}

override fun onFinished(result: EyeGazeLivenessResult) {
  // Handle callback
}

override fun onAllCornersUsed() {
  // Handle callback
}

override fun onCriticalFacePresenceLost() {
  // Handle callback
}

Passing Eye Gaze Liveness configuration to EyeGazeLivenessFragment

  • Replace data class EyeGazeLivenessConfiguration with EyeGazeLivenessFragment.Configuration.
  • Replace interface SegmentsGenerator and implementation RandomSegmentsGenerator with CornersGenerator and factory CornersGeneratorFactory.
  • Replace property Segment.durationMillis with EyeGazeLivenessFragment.Configuration.transitionDurationMillis.
  • Instead of passing the configuration as a fragment argument, override EyeGazeLivenessFragment.provideConfiguration() method.

Before

val segmentCount = 8
val segmentDurationMillis = 800
val segments = RandomSegmentsGenerator().generate(segmentCount, segmentDurationMillis)
val configuration = EyeGazeLivenessConfiguration.Builder(segments)
  .minFaceSizeRatio(0.1)
  .maxFaceSizeRatio(0.3)
  .transitionType(EyeGazeLivenessConfiguration.TransitionType.MOVE)
  .build()
val bundle = bundleOf(EyeGazeLivenessFragment.CONFIGURATION to configuration)
findNavController().navigate(R.id.action, bundle)

After

private val cornersGenerator = CornersGeneratorFactory.create()
...
override fun provideConfiguration() = Configuration(
  corners = cornersGenerator.generate(count = 8),
  faceSizeRatioInterval = IntervalDouble(min = 0.1, max = 1.3),
  transitionDurationMillis = 800,
  transitionType = Configuration.TransitionType.MOVE,
)