iOS'ta resimleri özel modelle etiketleme

Bir resimdeki varlıkları tanımak ve etiketlemek için ML Kit'i kullanabilirsiniz. Bu API, çok çeşitli özel resim sınıflandırma modellerini destekler. Model uyumluluk şartları, önceden eğitilmiş modellerin nerede bulunacağı ve kendi modellerinizin nasıl eğitileceği ile ilgili bilgiler için lütfen ML Kiti ile özel modeller bölümüne bakın.

Özel modeli entegre etmenin iki yolu vardır. 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ılmıştır.

Gruplandırılmış Model Barındırılan Model
Model, uygulamanızın APK'sının bir parçası olduğu için boyutunu artırır. Model, APK'nızın parçası değildir. Barındırılan Firebase Makine Öğrenimi.
Model, Android cihaz çevrimdışı olsa bile hemen kullanılabilir Model isteğe bağlı olarak indirildi
Firebase projesi gerekmez Firebase projesi gerektirir
Modeli güncellemek için uygulamanızı yeniden yayınlamanız gerekir Model güncellemelerini uygulamanızı yeniden yayınlamadan aktarın
Yerleşik A/B testi yok Firebase Remote Config ile kolay A/B testi

Deneyin

Başlamadan önce

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

    Bir modeli uygulamanızla gruplandırmak için:

    pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
    

    Bir modeli Firebase'den dinamik olarak indirmek için LinkFirebase bağımlı özelliğini ekleyin:

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

  3. Model indirmek istiyorsanız henüz eklemediyseniz Firebase'i iOS projenize ekleyin. Bu, modeli paket haline getirirken zorunlu değildir.

1. Modeli yükle

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

Modeli uygulamanızla birlikte paketlemek için:

  1. Model dosyasını (genellikle .tflite veya .lite ile biten) Xcode projenize kopyalayın, bunu yaparken Copy bundle resources öğesini seçmeye 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];

Firebase tarafından barındırılan model kaynağını yapılandırma

Uzaktan barındırılan modeli kullanmak için bir RemoteModel nesnesi oluşturun ve modeli yayınlarken verdiğiniz adı belirtin:

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, 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:

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 ilk kullanıma hazırlama kodunda başlatır. Ancak, modeli kullanmaya başlamadan önce bu işlemi dilediğiniz zaman yapabilirsiniz.

Resim etiketleyiciyi yapılandırma

Model kaynaklarınızı yapılandırdıktan sonra birinden ImageLabeler nesnesi oluşturun.

Aşağıdaki seçenekler kullanılabilir:

Seçenekler
confidenceThreshold

Algılanan etiketlerin minimum güven puanı. Ayarlanmazsa modelin meta verileri tarafından belirtilen tüm sınıflandırıcı eşikleri 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.

maxResultCount

Döndürülecek maksimum etiket sayısı. Politika ayarlanmazsa varsayılan değer olan 10 kullanılır.

Yalnızca yerel olarak paketlenmiş bir modeliniz varsa LocalModel nesnenizden bir etiket oluşturun:

Swift

let options = CustomImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = NSNumber(value: 0.0)
let imageLabeler = ImageLabeler.imageLabeler(options: options)

Objective-C

MLKCustomImageLabelerOptions *options =
    [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = @(0.0);
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

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

Etiketleyiciyi çalıştırmadan önce bunu onaylamanız gerekse de hem uzaktan barındırılan modeliniz hem de yerel olarak paketlenmiş bir modeliniz varsa ImageLabeler örneğini uygularken bu kontrolü yapmak mantıklı olabilir: İndirilmişse uzak modelden ve yerel modelden bir etiketleyici oluşturun.

Swift

var options: CustomImageLabelerOptions!
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = CustomImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = CustomImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = NSNumber(value: 0.0)
let imageLabeler = ImageLabeler.imageLabeler(options: options)

Objective-C

MLKCustomImageLabelerOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKCustomImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = @(0.0);
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

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

Varsayılan Bildirim Merkezi'ne gözlemciler ekleyerek modelin indirme durumunu görebilirsiniz. İndirme işlemleri uzun sürebileceğinden ve indirme işlemi tamamlandığında kaynak nesne serbest bırakılabileceğinden gözlemleyici bloğunda self için 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];
            }];

2. Giriş resmini hazırlayın

UIImage veya CMSampleBuffer kullanarak bir VisionImage nesnesi oluşturun.

UIImage kullanıyorsanız şu adımları uygulayın:

  • UIImage ile bir VisionImage nesnesi oluşturun. Doğru .orientation'u 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.

    Resmin yönünü ayarlamak 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];

3. Resim etiketleyiciyi çalıştırın

Bir resimdeki nesneleri etiketlemek için image nesnesini ImageLabeler öğesinin process() yöntemine geçirin.

Eşzamansız:

Swift

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

Objective-C

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

Eşzamanlı olarak:

Swift

var labels: [ImageLabel]
do {
    labels = try imageLabeler.results(in: image)
} catch let error {
    // Handle the error.
    return
}
// Show results.

Objective-C

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

4. Etiketli varlıklar hakkında bilgi edinin

Resim etiketleme işlemi başarılı olursa ImageLabel dizisini döndürür. Her ImageLabel, resimde etiketlenmiş olan bir öğeyi temsil eder. Her etiketin metin açıklamasını (TensorFlow Lite model dosyasının meta verilerinde varsa), güven puanını ve dizinini alabilirsiniz. Örneğin:

Swift

for label in labels {
  let labelText = label.text
  let confidence = label.confidence
  let index = label.index
}

Objective-C

for (MLKImageLabel *label in labels) {
  NSString *labelText = label.text;
  float confidence = label.confidence;
  NSInteger index = label.index;
}

Gerçek zamanlı performansı artırmak için ipuçları

Resimleri gerçek zamanlı bir uygulamada etiketlemek istiyorsanız en iyi kare hızlarına ulaşmak için şu yönergeleri izleyin:

  • Video çerçevelerini işlemek için algılayıcının results(in:) eşzamanlı API'sini kullanın. Belirtilen video çerçevesinden eşzamanlı olarak sonuç almak için AVCaptureVideoDataOutputSampleBufferDelegatecaptureOutput(_, didOutput:from:) işlevinden bu yöntemi çağırın. Algılayıcının çağrılarını kısmak için AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames değerini true olarak tutun. Algılayıcı çalışırken yeni bir video çerçevesi kullanılabilir hale gelirse atlanır.
  • Algılayıcının çıkışını giriş resmine yer paylaşımlı olarak eklemek için kullanıyorsanız önce ML Kit'ten sonucu alın, ardından resmi ve yer paylaşımını tek bir adımda oluşturun. Bu şekilde, her bir işlenmiş giriş çerçevesi için ekranı yalnızca bir kez oluşturursunuz. Örnek için ML Kit hızlı başlangıç örneğindeki updatepreviewOverlayViewWithLastFrame konusuna bakın.