iOS'te özel bir sınıflandırma modeliyle nesneleri algılama, izleme ve sınıflandırma

Ardışık video karelerindeki nesneleri algılayıp takip etmek için ML Kiti'ni kullanabilirsiniz.

Bir görüntüyü ML Kit'e ilettiğinizde bu cihaz, görüntüdeki her nesnenin konumuyla birlikte görüntüde beşe kadar nesne algılar. Video akışlarında nesneleri algılarken her nesnenin benzersiz bir kimliği vardır. Bu kimliği, nesneyi kareden kareye izlemek için kullanabilirsiniz.

Algılanan nesneleri sınıflandırmak için özel bir görüntü sınıflandırma modeli kullanabilirsiniz. Model uyumluluğu gereksinimleri, önceden eğitilmiş modellerin nerede bulunduğu ve kendi modellerinizi nasıl eğiteceğiniz hakkında yardım almak için lütfen ML Kit ile özel modeller bölümüne bakın.

Özel bir modeli iki şekilde entegre edebilirsiniz. Modeli uygulamanızın öğe klasörüne yerleştirerek paketleyebilir veya Firebase'den dinamik olarak indirebilirsiniz. Aşağıdaki tabloda iki seçenek karşılaştırılmaktadır.

Gruplandırılmış Model Barındırılan Model
Model, uygulamanızın .ipa dosyasının bir parçasıdır ve bu nedenle boyutu artırır. Model, uygulamanızın .ipa dosyasının bir parçası değil. Firebase Makine Öğrenimi'ne yüklenerek barındırılır.
Model, Android cihaz çevrimdışı olsa bile hemen kullanılabilir Model istek üzerine indirilir
Firebase projesine gerek yoktur Firebase projesi gereklidir
Modeli güncellemek için uygulamanızı yeniden yayınlamanız gerekir Uygulamanızı yeniden yayınlamadan model güncellemelerini aktarın
Yerleşik A/B testi yok Firebase Remote Config ile kolay A/B testi

Deneyin

Başlamadan önce

  1. ML Kit kitaplıklarını Podfile dosyanıza ekleyin:

    Uygulamanızla bir model paketi sunmak için:

    pod 'GoogleMLKit/ObjectDetectionCustom', '3.2.0'
    

    Firebase'den dinamik olarak bir model indirmek için LinkFirebase bağımlılığını ekleyin:

    pod 'GoogleMLKit/ObjectDetectionCustom', '3.2.0'
    pod 'GoogleMLKit/LinkFirebase', '3.2.0'
    
  2. Projenizin Kapsüllerini yükledikten veya güncelledikten sonra .xcworkspace ile Xcode projenizi açın. ML Kiti, 13.2.1 veya sonraki Xcode sürümlerinde desteklenir.

  3. Bir model indirmek istiyorsanız henüz yapmadıysanız Firebase'i iOS projenize eklediğinizden emin olun. Modeli paketlediğinizde bu gerekli değildir.

1. Modeli yükleme

Yerel model kaynağını yapılandırma

Modeli uygulamanızla birlikte gruplandırmak için:

  1. Model dosyasını (genellikle .tflite veya .lite ile biter) Xcode projenize kopyalayın ve bunu yaparken Copy bundle resources öğesini seçmeyi unutmayın. Model dosyası, uygulama paketine dahil edilir ve ML Kiti tarafından kullanılabilir.

  2. Model dosyasının yolunu belirterek LocalModel nesnesi oluşturun:

    Swift

    let localModel = LocalModel(path: localModelFilePath)

    Objective-C

    MLKLocalModel *localModel =
        [[MLKLocalModel alloc] initWithPath:localModelFilePath];

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 CustomRemoteModel nesnesi oluşturun:

Swift

let firebaseModelSource = FirebaseModelSource(
    name: "your_remote_model") // The name you assigned in
                               // the Firebase console.
let remoteModel = CustomRemoteModel(remoteModelSource: firebaseModelSource)

Objective-C

MLKFirebaseModelSource *firebaseModelSource =
    [[MLKFirebaseModelSource alloc]
        initWithName:@"your_remote_model"]; // The name you assigned in
                                            // the Firebase console.
MLKCustomRemoteModel *remoteModel =
    [[MLKCustomRemoteModel alloc]
        initWithRemoteModelSource:firebaseModelSource];

Ardından, indirme işlemine 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:

Swift

let downloadConditions = ModelDownloadConditions(
  allowsCellularAccess: true,
  allowsBackgroundDownloading: true
)

let downloadProgress = ModelManager.modelManager().download(
  remoteModel,
  conditions: downloadConditions
)

Objective-C

MLKModelDownloadConditions *downloadConditions =
    [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
                                         allowsBackgroundDownloading:YES];

NSProgress *downloadProgress =
    [[MLKModelManager modelManager] downloadModel:remoteModel
                                       conditions:downloadConditions];

Birçok uygulama, indirme görevini başlatma kodunda başlatır ancak modeli kullanmanız gerekmeden istediğiniz zaman bu işlemi gerçekleştirebilirsiniz.

2. Nesne algılayıcısını yapılandırın

Model kaynaklarınızı yapılandırdıktan sonra, bir CustomObjectDetectorOptions nesnesi kullanarak kullanım alanınız için nesne algılayıcıyı yapılandırın. Aşağıdaki ayarları değiştirebilirsiniz:

Nesne Algılayıcı Ayarları
Algılama modu STREAM_MODE (varsayılan) | SINGLE_IMAGE_MODE

Nesne algılayıcı, STREAM_MODE (varsayılan) ayarında düşük gecikmeyle çalışır ancak algılayıcının ilk birkaç çağrısında eksik sonuçlar (belirtilmemiş sınırlayıcı kutular veya kategori etiketleri gibi) üretebilir. Ayrıca, STREAM_MODE işlevinde algılayıcı, nesnelere izleme kimlikleri atar. Bu kimlikleri kareler genelinde nesneleri izlemek için kullanabilirsiniz. Nesneleri izlemek istediğinizde veya düşük gecikmenin önemli olduğu durumlarda (örneğin, video akışlarını gerçek zamanlı olarak işlerken) bu modu kullanın.

SINGLE_IMAGE_MODE ürününde nesne algılayıcı, nesnenin sınırlayıcı kutusu belirlendikten sonra sonucu döndürür. Sınıflandırmayı da etkinleştirirseniz sonucu, sınırlayıcı kutu ve kategori etiketi kullanılabilir hale geldikten sonra döndürür. Sonuç olarak algılama gecikmesi potansiyel olarak daha yüksek olur. Ayrıca, SINGLE_IMAGE_MODE içinde izleme kimlikleri atanmaz. Gecikme kritik değilse ve kısmi sonuçlarla uğraşmak istemiyorsanız bu modu kullanın.

Birden fazla nesneyi algılama ve izleme false (varsayılan) | true

En fazla beş nesnenin mı yoksa yalnızca en belirgin nesnenin mı (varsayılan) algılanacağını ve izleneceğini belirtir.

Nesneleri sınıflandırma false (varsayılan) | true

Sağlanan özel sınıflandırıcı modeli kullanılarak algılanan nesnelerin sınıflandırılıp sınıflandırılmayacağı. Özel sınıflandırma modelinizi kullanmak için bunu true olarak ayarlamanız gerekir.

Sınıflandırma güven eşiği

Algılanan etiketlerin minimum güven puanı. Ayarlanmazsa modelin meta verileri tarafından belirtilen herhangi bir sınıflandırıcı eşiği kullanılır. Model herhangi bir meta veri içermiyorsa veya meta veriler bir sınıflandırıcı eşiği belirtmiyorsa varsayılan eşik olan 0, 0 kullanılır.

Nesne başına maksimum etiket sayısı

Algılayıcının döndüreceği nesne başına maksimum etiket sayısı. Politika ayarlanmazsa 10 olan varsayılan değer kullanılır.

Yalnızca yerel olarak paketlenmiş bir modeliniz varsa LocalModel nesnenizden bir nesne algılayıcısı oluşturmanız yeterlidir:

Swift

let options = CustomObjectDetectorOptions(localModel: localModel)
options.detectorMode = .singleImage
options.shouldEnableClassification = true
options.shouldEnableMultipleObjects = true
options.classificationConfidenceThreshold = NSNumber(value: 0.5)
options.maxPerObjectLabelCount = 3

Objective-C

MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableClassification = YES;
options.shouldEnableMultipleObjects = YES;
options.classificationConfidenceThreshold = @(0.5);
options.maxPerObjectLabelCount = 3;

Uzaktan barındırılan bir modeliniz varsa çalıştırmadan önce modelin indirilip indirilmediğini kontrol etmeniz gerekir. Model yöneticisinin isModelDownloaded(remoteModel:) yöntemini kullanarak model indirme görevinin durumunu kontrol edebilirsiniz.

Nesne algılayıcıyı çalıştırmadan önce bunu doğrulamanız gerekse de hem uzaktan barındırılan bir modeliniz hem de yerel olarak paketlenmiş bir modeliniz varsa ObjectDetector için örnek oluştururken bu kontrolün yapılması mantıklı olabilir: İndirilmişse uzak modelden, aksi takdirde yerel modelden bir algılayıcı oluşturun.

Swift

var options: CustomObjectDetectorOptions!
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = CustomObjectDetectorOptions(remoteModel: remoteModel)
} else {
  options = CustomObjectDetectorOptions(localModel: localModel)
}
options.detectorMode = .singleImage
options.shouldEnableClassification = true
options.shouldEnableMultipleObjects = true
options.classificationConfidenceThreshold = NSNumber(value: 0.5)
options.maxPerObjectLabelCount = 3

Objective-C

MLKCustomObjectDetectorOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKCustomObjectDetectorOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
}
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableClassification = YES;
options.shouldEnableMultipleObjects = YES;
options.classificationConfidenceThreshold = @(0.5);
options.maxPerObjectLabelCount = 3;

Yalnızca uzaktan barındırılan bir modeliniz varsa modelin indirildiğini onaylayana kadar modelle ilgili işlevleri (örneğin, devre dışı bırakma veya kullanıcı arayüzünüzün bir bölümünü gizleme) devre dışı bırakmanız gerekir.

Modelin indirme durumunu, varsayılan Bildirim Merkezi'ne gözlemleyiciler ekleyerek alabilirsiniz. İndirme işlemi biraz zaman alabileceği ve indirme işlemi tamamlandığında kaynak nesne serbest bırakılabileceği için gözlemci bloğunda self öğesine zayıf bir referans kullandığınızdan emin olun. Örneğin:

Swift

NotificationCenter.default.addObserver(
    forName: .mlkitModelDownloadDidSucceed,
    object: nil,
    queue: nil
) { [weak self] notification in
    guard let strongSelf = self,
        let userInfo = notification.userInfo,
        let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
            as? RemoteModel,
        model.name == "your_remote_model"
        else { return }
    // The model was downloaded and is available on the device
}

NotificationCenter.default.addObserver(
    forName: .mlkitModelDownloadDidFail,
    object: nil,
    queue: nil
) { [weak self] notification in
    guard let strongSelf = self,
        let userInfo = notification.userInfo,
        let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
            as? RemoteModel
        else { return }
    let error = userInfo[ModelDownloadUserInfoKey.error.rawValue]
    // ...
}

Objective-C

__weak typeof(self) weakSelf = self;

[NSNotificationCenter.defaultCenter
    addObserverForName:MLKModelDownloadDidSucceedNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              MLKRemoteModel *model = note.userInfo[MLKModelDownloadUserInfoKeyRemoteModel];
              if ([model.name isEqualToString:@"your_remote_model"]) {
                // The model was downloaded and is available on the device
              }
            }];

[NSNotificationCenter.defaultCenter
    addObserverForName:MLKModelDownloadDidFailNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              NSError *error = note.userInfo[MLKModelDownloadUserInfoKeyError];
            }];

Nesne algılama ve izleme API'si aşağıdaki iki temel kullanım alanı için optimize edilmiştir:

  • Kamera vizöründeki en belirgin nesnenin canlı olarak algılanması ve izlenmesi.
  • Statik bir görüntüden birden fazla nesnenin algılanması.

API'yi bu kullanım alanlarına göre yapılandırmak için:

Swift

// Live detection and tracking
let options = CustomObjectDetectorOptions(localModel: localModel)
options.shouldEnableClassification = true
options.maxPerObjectLabelCount = 3

// Multiple object detection in static images
let options = CustomObjectDetectorOptions(localModel: localModel)
options.detectorMode = .singleImage
options.shouldEnableMultipleObjects = true
options.shouldEnableClassification = true
options.maxPerObjectLabelCount = 3

Objective-C

// Live detection and tracking
MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.shouldEnableClassification = YES;
options.maxPerObjectLabelCount = 3;

// Multiple object detection in static images
MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableMultipleObjects = YES;
options.shouldEnableClassification = YES;
options.maxPerObjectLabelCount = 3;

3. Giriş görüntüsünü hazırlama

UIImage veya CMSampleBuffer kullanarak VisionImage nesnesi oluşturun.

UIImage kullanıyorsanız aşağıdaki adımları uygulayın:

  • UIImage ile bir VisionImage nesnesi oluşturun. Doğru .orientation değerini belirttiğinizden emin olun.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

CMSampleBuffer kullanıyorsanız aşağıdaki adımları uygulayın:

  • CMSampleBuffer içinde yer alan resim verilerinin yönünü belirtin.

    Resmin yönünü öğrenmek için:

    Swift

    func imageOrientation(
      deviceOrientation: UIDeviceOrientation,
      cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
      switch deviceOrientation {
      case .portrait:
        return cameraPosition == .front ? .leftMirrored : .right
      case .landscapeLeft:
        return cameraPosition == .front ? .downMirrored : .up
      case .portraitUpsideDown:
        return cameraPosition == .front ? .rightMirrored : .left
      case .landscapeRight:
        return cameraPosition == .front ? .upMirrored : .down
      case .faceDown, .faceUp, .unknown:
        return .up
      }
    }
          

    Objective-C

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • CMSampleBuffer nesnesini ve yönünü kullanarak bir VisionImage nesnesi oluşturun:

    Swift

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    Objective-C

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

4. Nesne algılayıcısını oluşturup çalıştırın

  1. Yeni bir nesne algılayıcısı oluşturun:

    Swift

    let objectDetector = ObjectDetector.objectDetector(options: options)

    Objective-C

    MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];
  2. Ardından algılayıcıyı kullanın:

    Eş zamansız olarak:

    Swift

    objectDetector.process(image) { objects, error in
        guard error == nil, let objects = objects, !objects.isEmpty else {
            // Handle the error.
            return
        }
        // Show results.
    }

    Objective-C

    [objectDetector
        processImage:image
          completion:^(NSArray *_Nullable objects,
                       NSError *_Nullable error) {
            if (objects.count == 0) {
                // Handle the error.
                return;
            }
            // Show results.
         }];

    Eşzamanlı olarak:

    Swift

    var objects: [Object]
    do {
        objects = try objectDetector.results(in: image)
    } catch let error {
        // Handle the error.
        return
    }
    // Show results.

    Objective-C

    NSError *error;
    NSArray *objects =
        [objectDetector resultsInImage:image error:&error];
    // Show results or handle the error.

5. Etiketli nesneler hakkında bilgi alma

Görüntü işlemciye yapılan çağrı başarılı olursa tamamlama işleyicisine bir Object listesi iletir ya da eşzamansız veya eşzamanlı yöntemi çağırdığınıza bağlı olarak listeyi döndürür.

Her Object aşağıdaki özellikleri içerir:

frame Resimdeki nesnenin konumunu belirten bir CGRect.
trackingID Nesneyi resimler arasında tanımlayan bir tam sayı veya SINGLE_IMAGE_MODE işlevinde "nil".
labels
label.text Etiketin metin açıklaması. Yalnızca TensorFlow Lite modelinin meta verileri etiket açıklamaları içeriyorsa döndürülür.
label.index Sınıflandırıcı tarafından desteklenen tüm etiketler arasında etiketin dizini.
label.confidence Nesne sınıflandırmasının güven değeri.

Swift

// objects contains one item if multiple object detection wasn't enabled.
for object in objects {
  let frame = object.frame
  let trackingID = object.trackingID
  let description = object.labels.enumerated().map { (index, label) in
    "Label \(index): \(label.text), \(label.confidence), \(label.index)"
  }.joined(separator: "\n")
}

Objective-C

// The list of detected objects contains one item if multiple object detection
// wasn't enabled.
for (MLKObject *object in objects) {
  CGRect frame = object.frame;
  NSNumber *trackingID = object.trackingID;
  for (MLKObjectLabel *label in object.labels) {
    NSString *labelString =
        [NSString stringWithFormat:@"%@, %f, %lu",
                                   label.text,
                                   label.confidence,
                                   (unsigned long)label.index];
  }
}

Mükemmel bir kullanıcı deneyimi sağlama

En iyi kullanıcı deneyimi için uygulamanızda aşağıdaki yönergeleri uygulayın:

  • Nesnenin başarılı bir şekilde algılanması, nesnenin görsel karmaşıklığına bağlıdır. Az sayıda görsel özelliğe sahip nesnelerin algılanmaları için resmin daha büyük bir bölümünü kaplamaları gerekebilir. Kullanıcılara, algılamak istediğiniz nesne türlerinde iyi çalışan girdileri yakalama konusunda yol göstermeniz gerekir.
  • Sınıflandırma kullanırken, desteklenen kategorilere düzgün bir şekilde girmeyen nesneleri algılamak isterseniz bilinmeyen nesneler için özel işlem uygulayın.

Ayrıca, [ML Kit Material Design vitrin uygulaması][showcase-link]{: .external } ve Materyal Tasarım Makine öğrenimi destekli özellikler için kalıplar koleksiyonuna göz atın.

Performansı artırma

Nesne algılamayı gerçek zamanlı bir uygulamada kullanmak istiyorsanız en iyi kare hızlarına ulaşmak için şu yönergeleri uygulayın:

  • Çoğu cihaz yeterli kare hızı üretemeyeceğinden gerçek zamanlı bir uygulamada akış modunu kullanırken birden fazla nesne algılamayı kullanmayın.

  • Video karelerini işlemek için algılayıcının results(in:) eşzamanlı API'sini kullanın. Belirtilen video karesinden sonuçları eşzamanlı olarak almak için bu yöntemi AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) işlevinden çağırın. Çağrıları algılayıcıya kısıtlamak için AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames özelliğini true olarak bırakın. Algılayıcı çalışırken yeni bir video karesi kullanılabilir hale gelirse atlanır.
  • Algılayıcının çıkışını giriş görüntüsünün üzerine grafik yerleştirmek için kullanırsanız önce sonucu ML Kit'ten alın, ardından görüntüyü tek bir adımda oluşturun ve yer paylaşımlı yapın. Bu şekilde, işlenen her giriş çerçevesi için görüntü yüzeyinde yalnızca bir kez görüntü oluşturursunuz. Örneği görmek için ML Kit hızlı başlangıç örneğindeki updatePreviewOverlayViewWithLastFrame) örneğine bakın.