Görüntü ve videolardaki yüzleri algılamak için ML Kit'i kullanabilirsiniz.
Başlamadan önce
- Henüz yapmadıysanız Firebase'i Android projenize ekleyin.
- ML Kit Android kitaplıklarının bağımlılıkları modülünüzün (uygulama düzeyinde) Gradle dosyasına (genellikle
app/build.gradle
) eklenmelidir:apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' dependencies { // ... implementation 'com.google.firebase:firebase-ml-vision:24.0.3' // If you want to detect face contours (landmark detection and classification // don't require this additional model): implementation 'com.google.firebase:firebase-ml-vision-face-model:20.0.1' }
-
İsteğe bağlı ancak önerilir: Uygulamanız Play Store'dan yüklendikten sonra uygulamanızı, ML modelini cihaza otomatik olarak indirecek şekilde yapılandırın.
Bunun için uygulamanızın
AndroidManifest.xml
dosyasına aşağıdaki beyanı ekleyin: Yükleme sırasında model indirmelerini etkinleştirmezseniz model, algılayıcıyı ilk kez çalıştırdığınızda indirilir. İndirme işlemi tamamlanmadan önce gönderdiğiniz istekler sonuç vermez.<application ...> ... <meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="face" /> <!-- To use multiple models: android:value="face,model2,model3" --> </application>
Giriş resmi kuralları
ML Kit'in yüzleri doğru şekilde algılaması için giriş resimlerinin yeterli piksel verisiyle temsil edilen yüzler içermesi gerekir. Genel olarak, bir resimde tespit etmek istediğiniz her yüz en az 100x100 piksel olmalıdır. Yüzlerin dış çizgilerini tespit etmek istiyorsanız ML Kit daha yüksek çözünürlüklü giriş gerektirir: Her yüz en az 200x200 piksel olmalıdır.
Gerçek zamanlı bir uygulamada yüz algılıyorsanız giriş resimlerinin genel boyutlarını da dikkate alabilirsiniz. Daha küçük resimler daha hızlı işlenebilir. Bu nedenle, gecikmeyi azaltmak için resimleri daha düşük çözünürlüklerde çekin (yukarıdaki doğruluk koşullarını göz önünde bulundurarak) ve öznenin yüzünün görüntünün mümkün olduğunca büyük bir kısmını kaplamasını sağlayın. Ayrıca Gerçek zamanlı performansı iyileştirmeyle ilgili ipuçları başlıklı makaleyi de inceleyin.
Resmin odaklanmaması doğruluğu olumsuz etkileyebilir. Kabul edilebilir sonuçlar elde edemiyorsanız kullanıcıdan resmi yeniden çekmesini isteyin.
Yüzün kameraya göre yönü de ML Kit'in algıladığı yüz özelliklerini etkileyebilir. Yüz Algılama Kavramları başlıklı makaleyi inceleyin.
1. Yüz algılayıcıyı yapılandırma
Bir resme yüz algılama özelliğini uygulamadan önce yüz algılayıcının varsayılan ayarlarından herhangi birini değiştirmek istiyorsanız bu ayarları birFirebaseVisionFaceDetectorOptions
nesnesi ile belirtin.
Aşağıdaki ayarları değiştirebilirsiniz:
Ayarlar | |
---|---|
Performans modu |
FAST (varsayılan)
| ACCURATE
Yüz algılarken hıza veya doğruluğa öncelik verin. |
Önemli noktaları algılama |
NO_LANDMARKS (varsayılan)
| ALL_LANDMARKS
Yüz "landmark'larını (gözler, kulaklar, burun, yanaklar, ağız vb.) tespit etmeye çalışılıp çalışılmayacağı. |
Konturları algılama |
NO_CONTOURS (varsayılan)
| ALL_CONTOURS
Yüz özelliklerinin dış hatlarının algılanıp algılanmayacağı. Kontur, yalnızca resimdeki en belirgin yüz için algılanır. |
Yüzleri sınıflandırma |
NO_CLASSIFICATIONS (varsayılan)
| ALL_CLASSIFICATIONS
Yüzlerin "gülümsüyor" ve "gözler açık" gibi kategorilere ayrılıp ayrılmayacağı. |
Minimum kadran boyutu |
float (varsayılan: 0.1f )
Algılanacak yüzlerin resme göre minimum boyutu. |
Yüz izlemeyi etkinleştirme |
false (varsayılan) | true
Yüzlere, resimlerdeki yüzleri izlemek için kullanılabilecek bir kimlik atanıp atanmayacağı. Kontur algılama etkinleştirildiğinde yalnızca bir yüzün algılandığını ve bu nedenle yüz izlemenin yararlı sonuçlar vermediğini unutmayın. Bu nedenle ve algılama hızını artırmak için hem kenar algılama hem de yüz izlemeyi etkinleştirmeyin. |
Örneğin:
Java
// High-accuracy landmark detection and face classification FirebaseVisionFaceDetectorOptions highAccuracyOpts = new FirebaseVisionFaceDetectorOptions.Builder() .setPerformanceMode(FirebaseVisionFaceDetectorOptions.ACCURATE) .setLandmarkMode(FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS) .setClassificationMode(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS) .build(); // Real-time contour detection of multiple faces FirebaseVisionFaceDetectorOptions realTimeOpts = new FirebaseVisionFaceDetectorOptions.Builder() .setContourMode(FirebaseVisionFaceDetectorOptions.ALL_CONTOURS) .build();
Kotlin
// High-accuracy landmark detection and face classification val highAccuracyOpts = FirebaseVisionFaceDetectorOptions.Builder() .setPerformanceMode(FirebaseVisionFaceDetectorOptions.ACCURATE) .setLandmarkMode(FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS) .setClassificationMode(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS) .build() // Real-time contour detection of multiple faces val realTimeOpts = FirebaseVisionFaceDetectorOptions.Builder() .setContourMode(FirebaseVisionFaceDetectorOptions.ALL_CONTOURS) .build()
2. Yüz algılayıcıyı çalıştırma
Bir resimdeki yüzleri algılamak için cihazdaki birBitmap
, media.Image
, ByteBuffer
, bayt dizisi veya dosyadan FirebaseVisionImage
nesnesi oluşturun. Ardından FirebaseVisionImage
nesnesini FirebaseVisionFaceDetector
nesnesinin detectInImage
yöntemine iletin.
Yüz tanıma için en az 480x360 piksel boyutunda bir resim kullanmanız gerekir. Yüzleri gerçek zamanlı olarak tanımanız gerekiyorsa kareleri bu minimum çözünürlükte yakalamak gecikmeyi azaltmanıza yardımcı olabilir.
Resminizden bir
FirebaseVisionImage
nesnesi oluşturun.-
Bir
media.Image
nesnesindenFirebaseVisionImage
nesnesi oluşturmak için (ör. bir cihazın kamerasından resim çekerken)media.Image
nesnesini ve resmin dönme açısınıFirebaseVisionImage.fromMediaImage()
'ye iletin.CameraX kitaplığını kullanıyorsanız
OnImageCapturedListener
veImageAnalysis.Analyzer
sınıfları rotasyon değerini sizin için hesaplar. Bu nedenle,FirebaseVisionImage.fromMediaImage()
işlevini çağırmadan önce rotasyonu ML Kit'inROTATION_
sabitlerinden birine dönüştürmeniz yeterlidir:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
Resmin dönme açısını gösteren bir kamera kitaplığı kullanmıyorsanız bunu cihazın dönme açısını ve cihazdaki kamera sensörünün yönünü kullanarak hesaplayabilirsiniz:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private int getRotationCompensation(String cameraId, Activity activity, Context context) throws CameraAccessException { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int rotationCompensation = ORIENTATIONS.get(deviceRotation); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Throws(CameraAccessException::class) private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. val deviceRotation = activity.windowManager.defaultDisplay.rotation var rotationCompensation = ORIENTATIONS.get(deviceRotation) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
Ardından,
media.Image
nesnesini ve dönüş değeriniFirebaseVisionImage.fromMediaImage()
'e gönderin:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Dosya URI'sinden
FirebaseVisionImage
nesnesi oluşturmak için uygulama bağlamını ve dosya URI'siniFirebaseVisionImage.fromFilePath()
'a iletin. Bu, kullanıcıdan galeri uygulamasından bir resim seçmesini istemek içinACTION_GET_CONTENT
intent'i kullandığınızda kullanışlıdır.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- Bir
ByteBuffer
veya bayt dizisindenFirebaseVisionImage
nesnesi oluşturmak için önce,media.Image
girişi için yukarıda açıklandığı şekilde resim rotasyonunu hesaplayın.Ardından, resmin yüksekliğini, genişliğini, renk kodlama biçimini ve döndürülmüş durumunu içeren bir
FirebaseVisionImageMetadata
nesnesi oluşturun:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
FirebaseVisionImage
nesnesi oluşturmak için arabellek veya diziyi ve meta veri nesnesini kullanın:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
Bitmap
nesnesindenFirebaseVisionImage
nesnesi oluşturmak için:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
nesnesi tarafından temsil edilen resim dik olmalıdır ve ek döndürme işlemi gerekmemelidir.
-
FirebaseVisionFaceDetector
örneğini alın:Java
FirebaseVisionFaceDetector detector = FirebaseVision.getInstance() .getVisionFaceDetector(options);
Kotlin
val detector = FirebaseVision.getInstance() .getVisionFaceDetector(options)
Son olarak, resmi
detectInImage
yöntemine iletin:Java
Task<List<FirebaseVisionFace>> result = detector.detectInImage(image) .addOnSuccessListener( new OnSuccessListener<List<FirebaseVisionFace>>() { @Override public void onSuccess(List<FirebaseVisionFace> faces) { // Task completed successfully // ... } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin
val result = detector.detectInImage(image) .addOnSuccessListener { faces -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
3. Algılanan yüzler hakkında bilgi edinme
Yüz tanıma işlemi başarılı olursa başarı dinleyicisineFirebaseVisionFace
nesnelerinin listesi iletilir. Her FirebaseVisionFace
nesnesi, resimde algılanan bir yüzü temsil eder. Her yüz için giriş resmindeki sınırlayıcı koordinatlarını ve yüz algılayıcıyı bulması için yapılandırdığınız diğer bilgileri alabilirsiniz. Örneğin:
Java
for (FirebaseVisionFace face : faces) { Rect bounds = face.getBoundingBox(); float rotY = face.getHeadEulerAngleY(); // Head is rotated to the right rotY degrees float rotZ = face.getHeadEulerAngleZ(); // Head is tilted sideways rotZ degrees // If landmark detection was enabled (mouth, ears, eyes, cheeks, and // nose available): FirebaseVisionFaceLandmark leftEar = face.getLandmark(FirebaseVisionFaceLandmark.LEFT_EAR); if (leftEar != null) { FirebaseVisionPoint leftEarPos = leftEar.getPosition(); } // If contour detection was enabled: List<FirebaseVisionPoint> leftEyeContour = face.getContour(FirebaseVisionFaceContour.LEFT_EYE).getPoints(); List<FirebaseVisionPoint> upperLipBottomContour = face.getContour(FirebaseVisionFaceContour.UPPER_LIP_BOTTOM).getPoints(); // If classification was enabled: if (face.getSmilingProbability() != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) { float smileProb = face.getSmilingProbability(); } if (face.getRightEyeOpenProbability() != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) { float rightEyeOpenProb = face.getRightEyeOpenProbability(); } // If face tracking was enabled: if (face.getTrackingId() != FirebaseVisionFace.INVALID_ID) { int id = face.getTrackingId(); } }
Kotlin
for (face in faces) { val bounds = face.boundingBox val rotY = face.headEulerAngleY // Head is rotated to the right rotY degrees val rotZ = face.headEulerAngleZ // Head is tilted sideways rotZ degrees // If landmark detection was enabled (mouth, ears, eyes, cheeks, and // nose available): val leftEar = face.getLandmark(FirebaseVisionFaceLandmark.LEFT_EAR) leftEar?.let { val leftEarPos = leftEar.position } // If contour detection was enabled: val leftEyeContour = face.getContour(FirebaseVisionFaceContour.LEFT_EYE).points val upperLipBottomContour = face.getContour(FirebaseVisionFaceContour.UPPER_LIP_BOTTOM).points // If classification was enabled: if (face.smilingProbability != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) { val smileProb = face.smilingProbability } if (face.rightEyeOpenProbability != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) { val rightEyeOpenProb = face.rightEyeOpenProbability } // If face tracking was enabled: if (face.trackingId != FirebaseVisionFace.INVALID_ID) { val id = face.trackingId } }
Yüz kontürleri örneği
Yüz konturu algılama özelliğini etkinleştirdiğinizde, algılanan her yüz özelliğinin nokta listesini alırsınız. Bu noktalar, özelliğin şeklini temsil eder. Konturların nasıl temsil edildiğiyle ilgili ayrıntılar için Yüz Algılama Kavramlarına Genel Bakış başlıklı makaleyi inceleyin.
Aşağıdaki resimde bu noktaların bir yüzle nasıl eşlendiği gösterilmektedir (büyütmek için resmi tıklayın):
Gerçek zamanlı yüz algılama
Yüz algılamayı gerçek zamanlı bir uygulamada kullanmak istiyorsanız en iyi kare hızlarına ulaşmak için aşağıdaki yönergeleri uygulayın:
Yüz algılayıcıyı, yüz konturu algılama veya sınıflandırma ve yer işareti algılama özelliklerinden birini (ikisini birden değil) kullanacak şekilde yapılandırın:
Kontur algılama
Önemli nokta algılama
Sınıflandırma
Önemli nokta algılama ve sınıflandırma
Kontur algılama ve önemli nokta algılama
Kontur algılama ve sınıflandırma
Kontur algılama, önemli nokta algılama ve sınıflandırmaFAST
modunu etkinleştirin (varsayılan olarak etkindir).Resimleri daha düşük çözünürlükte çekmeyi deneyin. Ancak bu API'nin resim boyutu koşullarını da göz önünde bulundurun.
- Dedektöre yapılan çağrıları azaltın. Algılayıcı çalışırken yeni bir video karesi kullanılabilir hale gelirse kareyi bırakın.
- Giriş resmine grafik yerleştirmek için algılayıcının çıkışını kullanıyorsanız önce ML Kit'ten sonucu alın, ardından resmi ve yer paylaşımını tek bir adımda oluşturun. Böylece, her giriş çerçevesi için ekran yüzeyinde yalnızca bir kez oluşturma işlemi gerçekleştirirsiniz.
-
Camera2 API'yi kullanıyorsanız resimleri
ImageFormat.YUV_420_888
biçiminde kaydedin.Eski Camera API'yi kullanıyorsanız resimleri
ImageFormat.NV21
biçiminde çekin.