AutoML Vision Edge'i kullanarak kendi modelinizi eğittikten sonra, bu modeli uygulamanızda kullanarak görüntüleri etiketleyebilirsiniz.
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' implementation 'com.google.firebase:firebase-ml-vision-automl:18.0.5' }
1. Modeli yükleme
ML Kit, AutoML tarafından oluşturulan modellerinizi cihazda çalıştırır. Ancak ML Kit'i, modelinizi Firebase'den, yerel depolama alanından veya her ikisinden de uzaktan yükleyecek şekilde yapılandırabilirsiniz.
Modeli Firebase'de barındırarak yeni bir uygulama sürümü yayınlamadan güncelleyebilir ve farklı kullanıcı gruplarına dinamik olarak farklı modeller sunmak için Remote Config ve A/B Testing'ü kullanabilirsiniz.
Modeli yalnızca Firebase ile barındırarak sağlamak ve uygulamanızla birlikte paketlemek istemiyorsanız uygulamanızın ilk indirme boyutunu azaltabilirsiniz. Ancak model uygulamanızla birlikte paketlenmemişse uygulamanız modeli ilk kez indirene kadar modelle ilgili işlevlerin kullanılamayacağını unutmayın.
Modelinizi uygulamanızla birlikte paketleyerek Firebase'da barındırılan model kullanılamadığında uygulamanızın ML özelliklerinin çalışmaya devam etmesini sağlayabilirsiniz.
Firebase tarafından barındırılan bir model kaynağını yapılandırma
Uzaktan barındırılan modeli kullanmak için modeli yayınlarken atadığınız adı belirterek bir FirebaseAutoMLRemoteModel
nesnesi oluşturun:
// Specify the name you assigned in the Firebase console.
FirebaseAutoMLRemoteModel remoteModel =
new FirebaseAutoMLRemoteModel.Builder("your_remote_model").build();
// Specify the name you assigned in the Firebase console.
val remoteModel = FirebaseAutoMLRemoteModel.Builder("your_remote_model").build()
Ardından, indirmeye izin vermek istediğiniz koşulları belirterek model indirme görevini başlatın. Model cihazda yoksa veya modelin daha yeni bir sürümü varsa görev, modeli Firebase'den eşzamansız olarak indirir:
FirebaseModelDownloadConditions conditions = new FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build();
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
// Success.
}
});
val conditions = FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Success.
}
Birçok uygulama, indirme görevini başlatma kodunda başlatır ancak modeli kullanmadan önce dilediğiniz zaman bu işlemi yapabilirsiniz.
Yerel model kaynağını yapılandırma
Modeli uygulamanızla paket haline getirmek için:
- Modeli ve meta verilerini, Firebase konsolundan indirdiğiniz ZIP arşivinden çıkarın. Dosyaları, indirdiğiniz şekilde, herhangi bir değişiklik yapmadan (dosya adları dahil) kullanmanızı öneririz.
-
Modelinizi ve meta veri dosyalarını uygulama paketinize ekleyin:
- Projenizde öğe klasörü yoksa
app/
klasörünü sağ tıklayıp Yeni > Klasör > Öğe Klasörü'nü tıklayarak bir klasör oluşturun. - Model dosyalarını içerecek şekilde öğeler klasörünün altında bir alt klasör oluşturun.
model.tflite
,dict.txt
vemanifest.json
dosyalarını alt klasöre kopyalayın (üç dosyanın da aynı klasörde olması gerekir).
- Projenizde öğe klasörü yoksa
- Gradle'ın uygulamayı derleyip model dosyasını sıkıştırmamasını sağlamak için uygulamanızın
build.gradle
dosyasına aşağıdakileri ekleyin: Model dosyası uygulama paketine dahil edilir ve ML Kit tarafından ham öğe olarak kullanılabilir.android { // ... aaptOptions { noCompress "tflite" } }
- Model manifest dosyasının yolunu belirten bir
FirebaseAutoMLLocalModel
nesnesi oluşturun:FirebaseAutoMLLocalModel localModel = new FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build();
val localModel = FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build()
Modelinizden resim etiketleyici oluşturma
Model kaynaklarınızı yapılandırdıktan sonra bunlardan birinde FirebaseVisionImageLabeler
nesnesi oluşturun.
Yalnızca yerel olarak paketlenmiş bir modeliniz varsa FirebaseAutoMLLocalModel
nesnenizle bir etiketleyici oluşturup zorunlu kılmak istediğiniz güven puanı eşiğini yapılandırmanız yeterlidir (Modelinizi değerlendirme bölümüne bakın):
FirebaseVisionImageLabeler labeler;
try {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options =
new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build();
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// ...
}
val options = FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
Uzaktan barındırılan bir modeliniz varsa çalıştırmadan önce modelin indirildiğinden emin olmanız gerekir. Model yöneticisinin isModelDownloaded()
yöntemini kullanarak model indirme görevinin durumunu kontrol edebilirsiniz.
Bunu yalnızca etiketleyiciyi çalıştırmadan önce onaylamanız gerekir. Ancak hem uzakta barındırılan hem de yerel olarak paketlenmiş bir modeliniz varsa görüntü etiketleyiciyi örneklendirirken bu kontrolü gerçekleştirmeniz yararlı olabilir: İndirilmişse uzak modelden, indirilmediyse yerel modelden bir etiketleyici oluşturun.
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener(new OnSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder optionsBuilder;
if (isDownloaded) {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel);
} else {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel);
}
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options = optionsBuilder
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate threshold.
.build();
FirebaseVisionImageLabeler labeler;
try {
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// Error.
}
}
});
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener { isDownloaded ->
val optionsBuilder =
if (isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel)
} else {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
}
// Evaluate your model in the Firebase console to determine an appropriate threshold.
val options = optionsBuilder.setConfidenceThreshold(0.0f).build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
}
Yalnızca uzaktan barındırılan bir modeliniz varsa modelin indirildiğini onaylayana kadar modelle ilgili işlevleri (ör. kullanıcı arayüzünüzün bir bölümünü devre dışı bırakma veya gizleme) devre dışı bırakmanız gerekir. Bunu, model yöneticisinin download()
yöntemine bir dinleyici ekleyerek yapabilirsiniz:
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void v) {
// Download complete. Depending on your app, you could enable
// the ML feature, or switch from the local model to the remote
// model, etc.
}
});
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Download complete. Depending on your app, you could enable the ML
// feature, or switch from the local model to the remote model, etc.
}
2. Giriş resmini hazırlama
Ardından, etiketlemek istediğiniz her resim için bu bölümde açıklanan seçeneklerden birini kullanarak bir FirebaseVisionImage
nesnesi oluşturun ve bunu bir FirebaseVisionImageLabeler
örneğine (sonraki bölümde açıklanmaktadır) iletin.
Bir media.Image
nesnesinden, cihazdaki bir dosyadan, bayt dizisinden veya Bitmap
nesnesinden FirebaseVisionImage
nesnesi oluşturabilirsiniz:
-
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: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 // ... } }
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:
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; }
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:FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
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.FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
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:FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
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:FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
Bitmap
nesnesindenFirebaseVisionImage
nesnesi oluşturmak için:FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
nesnesi tarafından temsil edilen resim dik olmalıdır ve ek döndürme işlemi gerekmemelidir.
3. Resim etiketleyiciyi çalıştırma
Bir resimdeki nesneleri etiketlemek için FirebaseVisionImage
nesnesini FirebaseVisionImageLabeler
'un processImage()
yöntemine iletin.
labeler.processImage(image)
.addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionImageLabel>>() {
@Override
public void onSuccess(List<FirebaseVisionImageLabel> labels) {
// Task completed successfully
// ...
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// Task failed with an exception
// ...
}
});
labeler.processImage(image)
.addOnSuccessListener { labels ->
// Task completed successfully
// ...
}
.addOnFailureListener { e ->
// Task failed with an exception
// ...
}
Görüntü etiketleme başarılı olursa başarı dinleyicisine bir FirebaseVisionImageLabel
nesnesi dizisi iletilir. Her nesneden, resimde tanınan bir özellik hakkında bilgi edinebilirsiniz.
Örneğin:
for (FirebaseVisionImageLabel label: labels) {
String text = label.getText();
float confidence = label.getConfidence();
}
for (label in labels) {
val text = label.text
val confidence = label.confidence
}
Gerçek zamanlı performansı iyileştirmeye yönelik ipuçları
- 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.