Art arda gelen video karelerindeki nesneleri algılamak ve takip etmek için ML Kit'i kullanabilirsiniz.
Bir resmi ML Kit'e ilettiğinizde, resimdeki beşe kadar nesneyi algılar konumla birlikte resimdeki her bir nesnenin konumunu da içerir. Şu yolda nesneleri algılarken: her nesnenin, nesneyi izlemek için kullanabileceğiniz benzersiz bir kimliği vardır her kareden kareye geçelim. İsterseniz genel nesneyi de etkinleştirebilirsiniz. geniş kategori tanımlarına sahip nesneleri etiketleyen bir modeldir.
Deneyin
- Örnek uygulamayı kullanarak bu API'nin örnek kullanımını inceleyin.
- Materyal Tasarım vitrinini görün uygulamasının uçtan uca uygulanmasına olanak tanır.
Başlamadan önce
- Proje düzeyindeki
build.gradle
dosyanıza Google'ın Maven deposu hembuildscript
hem deallprojects
bölüm. - ML Kit Android kitaplıklarının bağımlılıklarını modülünüze
uygulama düzeyinde gradle dosyası vardır. Bu genellikle
app/build.gradle
olan:dependencies { // ... implementation 'com.google.mlkit:object-detection:17.0.2' }
1. Nesne algılayıcıyı yapılandırma
Nesneleri algılamak ve izlemek için önce ObjectDetector
örneği oluşturun ve
isteğe bağlı olarak
varsayılandır.
Nesne algılayıcıyı
ObjectDetectorOptions
nesne algılandı. Şunları değiştirebilirsiniz: Ayarlar:Nesne Algılayıcı Ayarları Algılama modu STREAM_MODE
(varsayılan) |SINGLE_IMAGE_MODE
STREAM_MODE
ürününde (varsayılan) nesne algılayıcısı çalışır düşük gecikme süresi vardır, ancak eksik sonuçlar oluşturabilir (ör. (belirtilmemiş sınırlayıcı kutular veya kategori etiketleri) yer alır. çağrılarına karşılık gelir. AyrıcaSTREAM_MODE
içinde, algılayıcı, nesnelere izleme kimlikleri atar. Bu kimlikleri çerçevelerde nesneleri izler. YouTube TV'yi izlemek istediğinizde veya veri işleme sırasında olduğu gibi düşük gecikmenin gerçek zamanlı video akışı sağlar.SINGLE_IMAGE_MODE
işlevinde, nesne algılayıcısı nesnenin sınırlayıcı kutusu belirlendikten sonra sonuç elde edilir. Şu durumda: sınıflandırmayı da etkinleştirdiğinde sınırlayıcıdan sonra sonucu döndürür kutu ve kategori etiketi kullanılabilir. Sonuç olarak algılama gecikmesi potansiyel olarak daha yüksektir. Ayrıca,SINGLE_IMAGE_MODE
, izleme kimlikleri atanmadı. Tekliflerinizi otomatikleştirmek ve optimize etmek için bu modu kullanırsanız ve gecikmeyle uğraşmak istemezseniz kısmi sonuçlar sağlar.Birden çok nesneyi algılama ve izleme false
(varsayılan) |true
Beş adede kadar veya yalnızca en fazla nesne algılayıp takip etme belirgin nesne (varsayılan).
Nesneleri sınıflandırma false
(varsayılan) |true
Algılanan nesnelerin genel kategorilerde sınıflandırılıp sınıflandırılmayacağı. Etkinleştirildiğinde, nesne algılayıcı, nesneleri şu kategoriler: moda ürünleri, gıda, ev eşyaları, yerler ve bitkiler.
Nesne algılama ve izleme API'si, bu iki temel kullanım için optimize edilmiştir vakalar:
- Kameradaki en belirgin nesnenin canlı algılanması ve takip edilmesi vizör.
- Statik görüntüden birden fazla nesnenin algılanması.
API'yi bu kullanım alanlarına göre yapılandırmak için:
Kotlin
// Live detection and tracking val options = ObjectDetectorOptions.Builder() .setDetectorMode(ObjectDetectorOptions.STREAM_MODE) .enableClassification() // Optional .build() // Multiple object detection in static images val options = ObjectDetectorOptions.Builder() .setDetectorMode(ObjectDetectorOptions.SINGLE_IMAGE_MODE) .enableMultipleObjects() .enableClassification() // Optional .build()
Java
// Live detection and tracking ObjectDetectorOptions options = new ObjectDetectorOptions.Builder() .setDetectorMode(ObjectDetectorOptions.STREAM_MODE) .enableClassification() // Optional .build(); // Multiple object detection in static images ObjectDetectorOptions options = new ObjectDetectorOptions.Builder() .setDetectorMode(ObjectDetectorOptions.SINGLE_IMAGE_MODE) .enableMultipleObjects() .enableClassification() // Optional .build();
ObjectDetector
örneği alın:Kotlin
val objectDetector = ObjectDetection.getClient(options)
Java
ObjectDetector objectDetector = ObjectDetection.getClient(options);
2. Giriş resmini hazırlama
Nesneleri algılamak ve izlemek için resimleriObjectDetector
cihazına iletin
örneğin process()
yöntemini kullanabilirsiniz.
Nesne algılayıcı, doğrudan bir Bitmap
, NV21 ByteBuffer
veya
YUV_420_888 media.Image
. Bu kaynaklardan bir InputImage
oluşturma
bunlardan birine doğrudan erişiminiz varsa önerilir. Bir
Diğer kaynaklardan InputImage
alındıysa dönüşümü biz hallederiz.
ve daha az verimli olabilir.
Bir dizideki her bir video veya resim karesi için aşağıdakileri yapın:
InputImage
oluşturabilirsiniz
her biri aşağıda açıklanmıştır.
media.Image
kullanarak
InputImage
oluşturmak için
media.Image
nesnesinden bir nesneden (örneğin,
cihazın kamerasını, media.Image
nesnesini ve resmin
döndürme değeri InputImage.fromMediaImage()
değerine ayarlanır.
URL'yi
CameraX kitaplığı, OnImageCapturedListener
ve
ImageAnalysis.Analyzer
sınıfları rotasyon değerini hesaplar
sizin için.
Kotlin
private class YourImageAnalyzer : ImageAnalysis.Analyzer { override fun analyze(imageProxy: ImageProxy) { val mediaImage = imageProxy.image if (mediaImage != null) { val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees) // Pass image to an ML Kit Vision API // ... } } }
Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { @Override public void analyze(ImageProxy imageProxy) { Image mediaImage = imageProxy.getImage(); if (mediaImage != null) { InputImage image = InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees()); // Pass image to an ML Kit Vision API // ... } } }
Resmin dönme derecesini sağlayan bir kamera kitaplığı kullanmıyorsanız cihazın dönüş derecesinden ve kameranın yönünden hesaplayabilir cihazdaki sensör:
Kotlin
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 0) ORIENTATIONS.append(Surface.ROTATION_90, 90) ORIENTATIONS.append(Surface.ROTATION_180, 180) ORIENTATIONS.append(Surface.ROTATION_270, 270) } /** * 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, isFrontFacing: Boolean): 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) // Get the device's sensor orientation. val cameraManager = activity.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360 } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360 } return rotationCompensation }
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 0); ORIENTATIONS.append(Surface.ROTATION_90, 90); ORIENTATIONS.append(Surface.ROTATION_180, 180); ORIENTATIONS.append(Surface.ROTATION_270, 270); } /** * 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, boolean isFrontFacing) 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); // Get the device's sensor orientation. CameraManager cameraManager = (CameraManager) activity.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360; } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360; } return rotationCompensation; }
Ardından, media.Image
nesnesini ve
döndürme derecesi değerini InputImage.fromMediaImage()
değerine ayarlayın:
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
Dosya URI'si kullanarak
InputImage
oluşturmak için
uygulama bağlamını ve dosya URI'sini
InputImage.fromFilePath()
. Bu özellik,
kullanıcıdan seçim yapmasını istemek için bir ACTION_GET_CONTENT
niyeti kullanın
galeri uygulamasından bir resim.
Kotlin
val image: InputImage try { image = InputImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
Java
InputImage image; try { image = InputImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
ByteBuffer
veya ByteArray
kullanarak
InputImage
oluşturmak için
bir ByteBuffer
veya ByteArray
nesnesinden alıp almayacaksanız önce resmi hesaplayın
media.Image
girişi için daha önce açıklandığı gibi dönme derecesi.
Ardından, arabellek veya diziyle InputImage
nesnesini, bu resmin
yükseklik, genişlik, renk kodlama biçimi ve döndürme derecesi:
Kotlin
val image = InputImage.fromByteBuffer( byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ) // Or: val image = InputImage.fromByteArray( byteArray, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 )
Java
InputImage image = InputImage.fromByteBuffer(byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ); // Or: InputImage image = InputImage.fromByteArray( byteArray, /* image width */480, /* image height */360, rotation, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 );
Bitmap
kullanarak
InputImage
oluşturmak için
Bitmap
nesnesindeki şu bildirimi yapın:
Kotlin
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
Resim, döndürme dereceleriyle birlikte bir Bitmap
nesnesiyle temsil edilir.
3. Resmi işleyin
Resmiprocess()
yöntemine geçirin:
Kotlin
objectDetector.process(image) .addOnSuccessListener { detectedObjects -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
Java
objectDetector.process(image) .addOnSuccessListener( new OnSuccessListener<List<DetectedObject>>() { @Override public void onSuccess(List<DetectedObject> detectedObjects) { // Task completed successfully // ... } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
4. Algılanan nesneler hakkında bilgi alma
process()
çağrısı başarılı olursa DetectedObject
içeren bir liste
yardımcı olur.
Her DetectedObject
aşağıdaki özellikleri içerir:
Sınırlayıcı kutu | NesneninRect
görüntüsüdür. |
||||||
İzleme Kimliği | Nesneyi resimler arasında tanımlayan bir tam sayı. Boş değer: TEK_IMAGE_MODE. | ||||||
Etiketler |
|
Kotlin
for (detectedObject in detectedObjects) { val boundingBox = detectedObject.boundingBox val trackingId = detectedObject.trackingId for (label in detectedObject.labels) { val text = label.text if (PredefinedCategory.FOOD == text) { ... } val index = label.index if (PredefinedCategory.FOOD_INDEX == index) { ... } val confidence = label.confidence } }
Java
// The list of detected objects contains one item if multiple // object detection wasn't enabled. for (DetectedObject detectedObject : detectedObjects) { Rect boundingBox = detectedObject.getBoundingBox(); Integer trackingId = detectedObject.getTrackingId(); for (Label label : detectedObject.getLabels()) { String text = label.getText(); if (PredefinedCategory.FOOD.equals(text)) { ... } int index = label.getIndex(); if (PredefinedCategory.FOOD_INDEX == index) { ... } float confidence = label.getConfidence(); } }
Mükemmel bir kullanıcı deneyimi sağlama
En iyi kullanıcı deneyimi için uygulamanızda aşağıdaki yönergelere uyun:
- Nesne algılama işleminin başarılı olması, nesnenin görsel karmaşıklığına bağlıdır. İçinde az sayıda görsel özelliği olan nesnelerin algılanması için kaplamaya başlar. Kullanıcılara şu konularda yol göstermeniz gerekir: algılamak istediğiniz tür nesnelerde iyi çalışan bir giriş yakalamanızı sağlar.
- Sınıflandırma kullanırken, düşmeyen nesneleri tespit etmek isterseniz desteklenen kategorilere ayırarak, bilinmeyen kullanıcılar için nesneler'i tıklayın.
Ayrıca, ML Kit Material Design vitrin uygulaması ve Materyal Tasarım Makine öğrenimi destekli özellikler koleksiyonu için kalıplar.
Performansı artırma
Nesne algılamayı gerçek zamanlı bir uygulamada kullanmak isterseniz aşağıdaki talimatları uygulayın:
Akış modunu gerçek zamanlı bir uygulamada kullanırken birden fazla nesne algılama özelliği vardır. Bunun nedeni, çoğu cihaz yeterli kare hızı üretememesidir.
İhtiyacınız yoksa sınıflandırmayı devre dışı bırakın.
- URL'yi
Camera
veyacamera2
API, algılayıcıya yapılan çağrıları kısıtlamaz. Yeni bir video çerçeve, algılayıcı çalışırken kullanılabilir hale gelirse çerçeveyi bırakın. Bkz. Örnek için hızlı başlangıç örnek uygulamasındakiVisionProcessorBase
sınıfı. CameraX
API'yi kullanıyorsanız karşı baskı stratejisinin varsayılan değerine ayarlandığından emin olunImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
) Bu, aynı anda yalnızca bir resmin analiz için gönderilmesini garanti eder. Daha fazla resim üretilirse analiz aracı meşgulken üretilirse otomatik olarak bırakılır ve teslimat. Analiz edilen resim, çağırarak kapatıldıktan sonra ImageProxy.close(), bir sonraki en son resim gönderilir.- Algılayıcının çıkışını, üzerine grafik yerleştirmek için
giriş görüntüsünü kullanın, önce ML Kit'ten sonucu alın ve ardından görüntüyü oluşturun
tek bir adımda yapabilirsiniz. Bu, görüntü yüzeyine oluşturulur
her giriş karesi için yalnızca bir kez. Bkz.
CameraSourcePreview
ve Hızlı başlangıç örnek uygulamasındakiGraphicOverlay
sınıflarına göz atın. - Camera2 API'sini kullanıyorsanız görüntüleri şurada yakalayın:
ImageFormat.YUV_420_888
biçimindedir. Eski Kamera API'sini kullanıyorsanız görüntüleri şurada yakalayın:ImageFormat.NV21
biçimindedir.