AutoML Vision Edge'i kullanarak kendi modelinizi eğittikten sonra, görüntüleri etiketlemek için uygulamanızda kullanabilirsiniz.
Başlamadan önce
- Henüz yapmadıysanız Firebase'i Android projenize ekleyin.
- ML Kit Android kitaplıklarına ait bağımlılıkları modülünüzün (uygulama düzeyinde) Gradle dosyasına (genellikle
app/build.gradle
) ekleyin: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 modeli güncelleyebilir ve farklı kullanıcılara dinamik olarak farklı modeller sunmak için Remote Config ile A/B Testing'i kullanabilirsiniz.
Modeli yalnızca Firebase ile barındırarak sağlamayı ve uygulamanızla birlikte paketlememeyi tercih ederseniz uygulamanızın ilk indirme boyutunu küçültebilirsiniz. Ancak modeli uygulamanızla birlikte paketlemezseniz modelle ilgili işlevlerin, uygulamanız modeli ilk kez indirene kadar kullanılamayacağını unutmayın.
Modelinizi uygulamanızla birlikte paketleyerek, Firebase'de barındırılan model kullanılamadığında uygulamanızın makine öğrenimi özelliklerinin çalışmaya devam etmesini sağlayabilirsiniz.
Firebase'de barındırılan bir model kaynağını yapılandırma
Uzaktan barındırılan modeli kullanmak için FirebaseAutoMLRemoteModel
nesnesi oluşturun.
Modeli yayınlarken atadığınız adı belirtin:
Java
// Specify the name you assigned in the Firebase console.
FirebaseAutoMLRemoteModel remoteModel =
new FirebaseAutoMLRemoteModel.Builder("your_remote_model").build();
Kotlin
// 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:
Java
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.
}
});
Kotlin
val conditions = FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Success.
}
Birçok uygulama, başlatma kodunda indirme görevini başlatır ancak modeli kullanmanız gerekmeden önce istediğiniz zaman bu işlemi yapabilirsiniz.
Yerel model kaynağı yapılandırma
Modeli uygulamanızla paketlemek için:
- Firebase konsolundan indirdiğiniz zip arşivinden modeli ve meta verilerini çıkarın. Dosyaları, dosya adları da dahil olmak üzere herhangi bir değişiklik yapmadan indirdiğiniz şekilde kullanmanızı öneririz.
-
Modelinizi ve meta veri dosyalarını uygulama paketinize ekleyin:
- Projenizde bir öğeler klasörü yoksa
app/
klasörünü sağ tıklayıp Yeni > Klasör > Öğeler 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 bir öğeler klasörü yoksa
- Gradle'ın uygulamayı oluştururken model dosyasını sıkıştırmadığından emin olmak için uygulamanızın
build.gradle
dosyasına aşağıdakileri ekleyin: Model dosyası, uygulama paketine dahil edilir ve ML Kit'e ham öğe olarak sunulur.android { // ... aaptOptions { noCompress "tflite" } }
- Model manifest dosyasına giden yolu belirterek bir
FirebaseAutoMLLocalModel
nesnesi oluşturun:Java
FirebaseAutoMLLocalModel localModel = new FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build();
Kotlin
val localModel = FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build()
Modelinizden resim etiketleyici oluşturma
Model kaynaklarınızı yapılandırdıktan sonra bunlardan birinden FirebaseVisionImageLabeler
nesne oluşturun.
Yalnızca yerel olarak paketlenmiş bir modeliniz varsa FirebaseAutoMLLocalModel
nesnenizden bir etiketleyici oluşturmanız ve gerekli güven puanı eşiğini yapılandırmanız yeterlidir (bkz. Modelinizi değerlendirme):
Java
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) {
// ...
}
Kotlin
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 indirildiğinden emin olmanız gerekir. Model yöneticisinin isModelDownloaded()
yöntemini kullanarak model indirme görevinin durumunu kontrol edebilirsiniz.
Bu işlemi yalnızca etiketleyiciyi çalıştırmadan önce onaylamanız gerekse de hem uzaktan barındırılan hem de yerel olarak paketlenmiş bir modeliniz varsa görüntü etiketleyiciyi oluştururken bu kontrolü yapmanız mantıklı olabilir: İndirildiyse uzaktan modelden, aksi takdirde yerel modelden bir etiketleyici oluşturun.
Java
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.
}
}
});
Kotlin
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:
Java
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.
}
});
Kotlin
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 FirebaseVisionImage
nesnesi oluşturun ve bunu FirebaseVisionImageLabeler
örneğine (sonraki bölümde açıklanmıştır) iletin.
FirebaseVisionImage
nesnesini media.Image
nesnesinden, cihazdaki bir dosyadan, bir bayt dizisinden veya bir Bitmap
nesnesinden oluşturabilirsiniz:
-
Bir
media.Image
nesnesindenFirebaseVisionImage
nesnesi oluşturmak için (ör. bir cihazın kamerasından görüntü yakalarken)media.Image
nesnesini ve görüntünün dönüşünüFirebaseVisionImage.fromMediaImage()
'ye iletin.CameraX kitaplığını kullanıyorsanız
OnImageCapturedListener
veImageAnalysis.Analyzer
sınıfları sizin için döndürme değerini hesaplar. Bu nedenle,FirebaseVisionImage.fromMediaImage()
işlevini çağırmadan önce döndürmeyi 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önüşünü sağlayan bir kamera kitaplığı kullanmıyorsanız, cihazın dönüşünden ve cihazdaki kamera sensörünün yönünden 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()
'ye iletin: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()
'ye iletin. Bu, kullanıcıdan galeri uygulamasından bir resim seçmesini istemek içinACTION_GET_CONTENT
amacını kullandığınızda yararlı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() }
ByteBuffer
veya bayt dizisindenFirebaseVisionImage
nesnesi oluşturmak için öncemedia.Image
girişi için yukarıda açıklandığı şekilde görüntü döndürme işlemini hesaplayın.Ardından, resmin yüksekliğini, genişliğini, renk kodlama biçimini ve dönüşünü 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()
Bir
FirebaseVisionImage
nesnesi oluşturmak için arabelleği 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)
FirebaseVisionImage
nesnesindenBitmap
nesnesi oluşturmak için:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
nesnesiyle gösterilen resim dik olmalı ve ek döndürme işlemi gerektirmemelidir.
3. Resim etiketleyiciyi çalıştırma
Resimdeki nesneleri etiketlemek için FirebaseVisionImage
nesnesini FirebaseVisionImageLabeler
'nin processImage()
yöntemine iletin.
Java
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
// ...
}
});
Kotlin
labeler.processImage(image)
.addOnSuccessListener { labels ->
// Task completed successfully
// ...
}
.addOnFailureListener { e ->
// Task failed with an exception
// ...
}
Resim etiketleme başarılı olursa başarı dinleyicisine FirebaseVisionImageLabel
nesne dizisi
geçirilir. Her nesneden, resimde tanınan bir özellik hakkında bilgi edinebilirsiniz.
Örneğin:
Java
for (FirebaseVisionImageLabel label: labels) {
String text = label.getText();
float confidence = label.getConfidence();
}
Kotlin
for (label in labels) {
val text = label.text
val confidence = label.confidence
}
Anlık performansı artırmaya yönelik ipuçları
- Dedektöre yapılan çağrıları sınırlayın. Algılayıcı çalışırken yeni bir video karesi kullanılabilir hale gelirse kareyi bırakın.
- Dedektörün çıkışını giriş resmine grafik yerleştirmek için kullanıyorsanız önce ML Kit'ten sonucu alın, ardından resmi tek adımda oluşturup yerleştirin. Bunu yaptığınızda, her giriş çerçevesi için yalnızca bir kez görüntüleme yüzeyine işleme yaparsınız.
-
Camera2 API'yi kullanıyorsanız görüntüleri
ImageFormat.YUV_420_888
biçiminde çekin.Eski Camera API'yi kullanıyorsanız görüntüleri
ImageFormat.NV21
biçiminde çekin.