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

ML Kit'i kullanarak ardışık video karelerindeki nesneleri algılayıp izleyebilirsiniz.

ML Kit'e bir resim ilettiğinizde, resimdeki her nesnenin konumuyla birlikte resimde en fazla beş nesne algılar. Video akışlarındaki nesneleri algılarken her nesnenin, nesneyi kareden kareye takip etmek için kullanabileceğiniz benzersiz bir kimliği vardır.

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 bulunacağı ve kendi modellerinizi nasıl eğiteceğinizle ilgili yönergeler için ML Kit ile özel modeller başlıklı makaleyi inceleyin.

Özel bir modeli entegre etmenin iki yolu vardır. Modeli, uygulamanızın öğe klasörüne koyarak paketleyebilir veya Cloud Storage'dan dinamik olarak indirebilirsiniz. Aşağıdaki tabloda iki seçenek karşılaştırılmaktadır.

Paketlenmiş Model Barındırılan Model
Model, uygulamanızın .ipa dosyasının bir parçasıdır ve bu dosyanın boyutunu artırır. Model, uygulamanızın .ipa dosyasının bir parçası değildir. Cloud Storage'a yüklenerek barındırılır. Firebase için Cloud Storage'ı kullanmanızı öneririz.
Model, Android cihaz çevrimdışı olsa bile hemen kullanılabilir. Uygulamanız, modeli isteğe bağlı olarak indirmek için kod içermelidir.
Firebase projesi gerekmez Firebase projesi gerektirir (Cloud Storage for Firebase kullanılıyorsa).
Modeli güncellemek için uygulamanızı yeniden yayınlamanız gerekir. Uygulamanızı yeniden yayınlamadan model güncellemelerini gönderme
Yerleşik A/B testi yok Firebase Remote Config ile A/B testi

Deneyin

Başlamadan önce

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

    pod 'GoogleMLKit/ObjectDetectionCustom', '8.0.0'
    
  2. Projenizin Pod'larını yükledikten veya güncelledikten sonra Xcode projenizi .xcworkspace kullanarak açın. ML Kit, Xcode 13.2.1 veya sonraki sürümlerde desteklenir.

  3. Cloud Storage for Firebase kullanarak bir model indirmek istiyorsanız, henüz yapmadıysanız Firebase'i iOS projenize eklediğinizden emin olun. Bu işlem, modeli paketlediğinizde gerekli değildir.

1. Modeli yükleme

Yerel model kaynağı yapılandırma

Modeli uygulamanızla paketlemek için:

  1. Model dosyasını (genellikle .tflite veya .lite ile biter) Xcode projenize kopyalayın. Bunu yaparken Copy bundle resources seçeneğini belirlemeye dikkat edin. Model dosyası, uygulama paketine dahil edilir ve ML Kit 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];

Uzaktan barındırılan model kaynağını yapılandırma

Uzaktan barındırılan modeli kullanmak için model dosyasını kendi uygulama mantığınızı kullanarak cihazın yerel depolama alanına indirmeniz ve ardından yerel model olarak yüklemeniz gerekir. Bir modeli barındırmak için Firebase için Cloud Storage'ı kullanmanızı öneririz. Uygulama ayrıntıları için Firebase ML'den Cloud Storage'a taşıma kılavuzuna bakın.

2. Nesne algılayıcıyı yapılandırma

Model kaynaklarınızı yapılandırdıktan sonra, CustomObjectDetectorOptions nesnesiyle kullanım alanınız için nesne dedektörünü 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

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

SINGLE_IMAGE_MODE içinde, nesne algılayıcı, nesnenin sınırlayıcı kutusu belirlendikten sonra sonucu döndürür. Sınıflandırmayı da etkinleştirirseniz hem sınırlayıcı kutu hem de kategori etiketi kullanılabilir olduğunda sonuç döndürülür. Sonuç olarak, algılama gecikmesi daha yüksek olabilir. 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 mi yoksa yalnızca en belirgin nesnenin mi (varsayılan) algılanıp izleneceği.

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

Algılanan nesnelerin, sağlanan özel sınıflandırıcı modeli kullanılarak sınıflandırılıp sınıflandırılmayacağı. Özel sınıflandırma modelinizi kullanmak için bu değeri true olarak ayarlamanız gerekir.

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

Algılanan etiketlerin minimum güven puanı. Ayarlanmazsa modelin meta verilerinde belirtilen sınıflandırıcı eşiği kullanılır. Modelde herhangi bir meta veri yoksa veya meta verilerde bir sınıflandırıcı eşiği belirtilmemişse varsayılan eşik olarak 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ı. Ayarlanmazsa varsayılan değer olan 10 kullanılır.

Yalnızca yerel olarak paketlenmiş bir modeliniz varsa LocalModel nesnenizden bir nesne algılayıcı 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 indirildiğinden emin olmanız gerekir.

Bu işlemi yalnızca nesne algılayıcıyı çalıştırmadan önce onaylamanız gerekse de hem uzaktan barındırılan hem de yerel olarak paketlenmiş bir modeliniz varsa ObjectDetector oluşturulurken bu kontrolü yapmak mantıklı olabilir: Uzak model indirilmişse bu modelden, aksi takdirde yerel modelden bir algılayıcı oluşturun.

Swift

// Path where your download logic saves the model
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite")

let model: LocalModel
if FileManager.default.fileExists(atPath: localModelURL.path) {
  // Use the downloaded model
  model = LocalModel(path: localModelURL.path)
} else {
  // Fall back to bundled model
  guard let bundledModelPath = Bundle.main.path(forResource: "model", ofType: "tflite") else { return }
  model = LocalModel(path: bundledModelPath)
}

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

Objective-C

NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"];

MLKLocalModel *model;
if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) {
  // Use the downloaded model
  model = [[MLKLocalModel alloc] initWithPath:localModelPath];
} else {
  // Fall back to bundled model
  NSString *bundledModelPath = [NSBundle.mainBundle pathForResource:@"model" ofType:@"tflite"];
  model = [[MLKLocalModel alloc] initWithPath:bundledModelPath];
}

MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:model];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableClassification = YES;
options.shouldEnableMultipleObjects = YES;
options.classificationConfidenceThreshold = @(0.5);
options.maxPerObjectLabelCount = 3;
MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions: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.

Swift

let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite")
if FileManager.default.fileExists(atPath: localModelURL.path) {
  // Model is already cached, initialize immediately
  self.initializeDetector(with: localModelURL)
} else {
  // Model is not yet available, show loading UI and start download
  self.showLoadingUI()
  let storage = Storage.storage()
  let modelRef = storage.reference(forURL: "gs://YOUR_BUCKET/path/to/model.tflite")
  modelRef.write(toFile: localModelURL) { url, error in
    self.hideLoadingUI()
    if let error = error {
      // Handle download error
      self.showErrorUI()
    } else if let modelURL = url {
      // Download success, initialize detector
      self.initializeDetector(with: modelURL)
    }
  }
}

func initializeDetector(with modelURL: URL) {
  let localModel = LocalModel(path: modelURL.path)
  let options = CustomObjectDetectorOptions(localModel: localModel)
  options.detectorMode = .singleImage
  options.shouldEnableClassification = true
  options.shouldEnableMultipleObjects = true
  self.objectDetector = ObjectDetector.objectDetector(options: options)
  // Enable ML features in UI
  self.enableMLFeatures()
}

Objective-C

NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"];
NSURL *localModelURL = [NSURL fileURLWithPath:localModelPath];

if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) {
  // Model is already cached, initialize immediately
  [self initializeDetectorWithURL:localModelURL];
} else {
  // Model is not yet available, show loading UI and start download
  [self showLoadingUI];

  FIRStorage *storage = [FIRStorage storage];
  FIRStorageReference *modelRef = [storage referenceForURL:@"gs://YOUR_BUCKET/path/to/model.tflite"];

  [modelRef writeToFile:localModelURL
             completion:^(NSURL * _Nullable URL, NSError * _Nullable error) {
               [self hideLoadingUI];
               if (error != nil) {
                 // Handle download error
                 [self showErrorUI];
               } else {
                 // Download success, initialize detector
                 [self initializeDetectorWithURL:URL];
               }
             }];
}

- (void)initializeDetectorWithURL:(NSURL *)modelURL {
  MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:modelURL.path];
  MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
  options.detectorMode = MLKObjectDetectorModeSingleImage;
  options.shouldEnableClassification = YES;
  options.shouldEnableMultipleObjects = YES;
  self.objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];

  // Enable ML features in UI
  [self enableMLFeatures];
}

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üdeki birden fazla nesnenin algılanması.

API'yi bu kullanım alanları için yapılandırmak üzere:

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 şu adımları uygulayın:

  • UIImage ile 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 şu adımları uygulayın:

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

    Resim yönünü almak 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 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ıyı oluşturma ve çalıştırma

  1. Yeni bir nesne algılayıcı 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, tamamlanma işleyicisine bir Object listesi iletir veya eşzamansız ya da eşzamanlı yöntemi çağırmanıza bağlı olarak listeyi döndürür.

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

frame Nesnenin resimdeki konumunu gösteren bir CGRect.
trackingID Nesneyi resimler arasında tanımlayan bir tam sayı veya SINGLE_IMAGE_MODE'da "nil".
labels
label.text Etiketin metin açıklaması. Yalnızca LiteRT 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ındaki 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:

  • Nesne tespit etmenin başarılı olması, nesnenin görsel karmaşıklığına bağlıdır. Az sayıda görsel özelliğe sahip nesnelerin tespit edilebilmesi için görüntünün daha büyük bir bölümünü kaplaması gerekebilir. Kullanıcılara, tespit etmek istediğiniz nesne türleriyle iyi çalışan girişler yakalama konusunda rehberlik etmelisiniz.
  • Sınıflandırma kullandığınızda, desteklenen kategorilere net bir şekilde girmeyen nesneleri algılamak istiyorsanız bilinmeyen nesneler için özel işlem uygulayın.

Ayrıca, ML Kit Materyal Tasarım vitrin uygulamasına ve Materyal Tasarım Makine öğrenimi destekli özellikler için kalıplar koleksiyonuna da göz atın.

Performansı artırma

Nesne tespit etmeyi gerçek zamanlı bir uygulamada kullanmak istiyorsanız en iyi kare hızlarını elde etmek için aşağıdaki yönergeleri uygulayın:

  • Gerçek zamanlı bir uygulamada akış modunu kullanırken çoğu cihaz yeterli kare hızını sağlayamayacağından birden fazla nesne tespit etme kullanmayın.

  • Video karelerini işlemek için algılayıcının results(in:) senkron API'sini kullanın. Belirli bir video karesinden sonuçları eşzamanlı olarak almak için bu yöntemi AVCaptureVideoDataOutputSampleBufferDelegate'ın captureOutput(_, didOutput:from:) işlevinden çağırın. Dedektöre yapılan aramaları sınırlamak için AVCaptureVideoDataOutput'nın alwaysDiscardsLateVideoFrames değerini true olarak tutun. Algılayıcı çalışırken yeni bir video karesi kullanılabilir hale gelirse bu kare bırakılır.
  • Grafikleri giriş resmine 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 yerleşimi tek adımda oluşturun. Böylece, işlenen her giriş karesi için yalnızca bir kez görüntüleme yüzeyine oluşturma işlemi yaparsınız. Bir örnek için ML Kit hızlı başlangıç örneğindeki updatePreviewOverlayViewWithLastFrame'e bakın.