googlesamples / mlkit

A collection of sample apps to demonstrate how to use Google's ML Kit APIs on Android and iOS
Apache License 2.0
3.58k stars 2.93k forks source link

MlKitContext has not been initialized #249

Closed DurgaArunkumarSmitiv closed 3 years ago

DurgaArunkumarSmitiv commented 3 years ago

For Face Detection,implemented as it is in sample, getting expected output. But when trying to run Face detection in Foreground Service it is throwing java.lang.IllegalStateException: MlKitContext has not been initialized. Below is code,As like activity implemented in service but its crashing. Not able to pass Service context to MlKitContext Class. Can you please help me in solving "MlKitContext has not been initialized." issue. Activity private var cameraSource: CameraSource? = null

cameraSource = CameraSource(this@MainActivity) cameraSource!!.setMachineLearningFrameProcessor( FaceDetectorProcessor(this@MainActivity) ) try { if (cameraSource != null) { val c = CameraSourcePreview(this@MainActivity) c.start(cameraSource) } } catch (e: Exception) { e.printStackTrace() }

FaceDetectorProcessor Class class FaceDetectorProcessor(context: Context) : VisionProcessorBase<List>(context) {

private val detector: FaceDetector

init { val options = FaceDetectorOptions.Builder() .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_FAST) .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL) .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL) .setMinFaceSize(0.1f) .build() detector = FaceDetection.getClient(options) Log.v(MANUAL_TESTING_LOG, "Face detector options: $options")

}

override fun stop() { super.stop() detector.close() }

override fun detectInImage(image: InputImage): Task<List> { return detector.process(image) }

override fun onSuccess(faces: List) { for (face in faces) { logExtrasForTesting(face) } }

override fun onFailure(e: Exception) { Log.e(TAG, "Face detection failed $e") }

companion object { private const val TAG = "FaceDetectorProcessor" private fun logExtrasForTesting(face: Face?) { if (face != null) { Log.v( MANUAL_TESTING_LOG, "face bounding box: " + face.boundingBox.flattenToString() ) Log.v( MANUAL_TESTING_LOG, "face Euler Angle X: " + face.headEulerAngleX ) Log.v( MANUAL_TESTING_LOG, "face Euler Angle Y: " + face.headEulerAngleY ) Log.v( MANUAL_TESTING_LOG, "face Euler Angle Z: " + face.headEulerAngleZ ) // All landmarks val landMarkTypes = intArrayOf( FaceLandmark.MOUTH_BOTTOM, FaceLandmark.MOUTH_RIGHT, FaceLandmark.MOUTH_LEFT, FaceLandmark.RIGHT_EYE, FaceLandmark.LEFT_EYE, FaceLandmark.RIGHT_EAR, FaceLandmark.LEFT_EAR, FaceLandmark.RIGHT_CHEEK, FaceLandmark.LEFT_CHEEK, FaceLandmark.NOSE_BASE ) val landMarkTypesStrings = arrayOf( "MOUTH_BOTTOM", "MOUTH_RIGHT", "MOUTH_LEFT", "RIGHT_EYE", "LEFT_EYE", "RIGHT_EAR", "LEFT_EAR", "RIGHT_CHEEK", "LEFT_CHEEK", "NOSE_BASE" ) for (i in landMarkTypes.indices) { val landmark = face.getLandmark(landMarkTypes[i]) if (landmark == null) { Log.v( MANUAL_TESTING_LOG, "No landmark of type: " + landMarkTypesStrings[i] + " has been detected" ) } else { val landmarkPosition = landmark.position val landmarkPositionStr = String.format(Locale.US, "x: %f , y: %f", landmarkPosition.x, landmarkPosition.y) Log.v( MANUAL_TESTING_LOG, "Position for face landmark: " + landMarkTypesStrings[i] + " is :" + landmarkPositionStr ) } } Log.v( MANUAL_TESTING_LOG, "face left eye open probability: " + face.leftEyeOpenProbability ) Log.v( MANUAL_TESTING_LOG, "face right eye open probability: " + face.rightEyeOpenProbability ) Log.v( MANUAL_TESTING_LOG, "face smiling probability: " + face.smilingProbability ) Log.v( MANUAL_TESTING_LOG, "face tracking id: " + face.trackingId ) } } } }

Activity Output image-20210317-171404

Service Output image-20210317-171032

sheepmaster commented 3 years ago

ML Kit usually automatically initializes itself at application startup, but that doesn't work in a foreground service. Try calling MlKit.initialize() before using the API.

DurgaArunkumarSmitiv commented 3 years ago

Thank you! it worked now after MlKit.initialize(). Also I am trying to find the distance between the device and face accurately, now i am using landmark face.getLandmark(FaceLandmark.LEFT_EYE) and face.getLandmark(FaceLandmark.RIGHT_EYE) but still seems it is not accurate. Is there a way to find the distance between face and device accurately using mlkit.

ai-plays commented 3 years ago

The image we send to the Face API is just a 2d image without depth info, so it is hard for the API to give meaningful hint about distance. You could probably try several workaround based on your specific use case.

As you mentioned already, measuring the distance between eyes could be a good start. Depending on your purpose, if you just want to not let the user stay too close to the camera, measuring the size of the face relatively to the entire image might also be helpful.

Another thing I am not super sure is that: maybe you could make use of some metadata of the image or some configuration about the camera device to know, for example, focal length... then combine that with the pixel eye distance on image to calculate the real distance. Just brainstorming... never tried it before.

Since this is not related to the question you posted at the beginning any more. If you would like to discuss more, could you open another issue?

DurgaArunkumarSmitiv commented 3 years ago

Yes, Thank you!

ber4444 commented 3 years ago

I'm also getting a IllegalStateException: MlKitContext has not been initialized crash in EntityExtraction.getClient which is called in Application.onCreate. @DurgaArunkumarSmitiv how do I declare the content provider in the manifest? The need for it is called out at https://developers.google.com/android/reference/com/google/mlkit/common/MlKit#initialize(android.content.Context) but the syntax is not explained.

ber4444 commented 3 years ago

I have

        <meta-data
            android:name="com.google.mlkit.vision.DEPENDENCIES"
            android:value="..." />

but it is not enough

sheepmaster commented 3 years ago

This is addressed in issue #264.