Memberi label pada gambar dengan model kustom di iOS

Anda dapat menggunakan ML Kit untuk mengenali entity dalam gambar dan melabelinya. API ini mendukung berbagai model klasifikasi gambar kustom. Memohon lihat Model kustom dengan ML Kit untuk mendapatkan panduan tentang persyaratan kompatibilitas model, tempat menemukan model terlatih, dan cara melatih model Anda sendiri.

Ada dua cara untuk mengintegrasikan model kustom. Anda dapat memaketkan model dengan memasukkannya ke dalam folder aset aplikasi, atau Anda dapat mendownloadnya secara dinamis dari Firebase. Tabel berikut membandingkan kedua opsi tersebut.

Model Paket Model yang Dihosting
Model ini adalah bagian dari APK aplikasi yang akan memperbesar ukurannya. Model bukan merupakan bagian dari APK Anda. Dokumen ini dihosting dengan diupload ke Machine Learning Firebase.
Model akan langsung tersedia, bahkan saat perangkat Android sedang offline Model didownload sesuai permintaan
Tidak memerlukan project Firebase Memerlukan project Firebase
Anda harus memublikasikan ulang aplikasi untuk memperbarui model Update model dapat dikirim tanpa memublikasikan ulang aplikasi
Tidak ada pengujian A/B bawaan Pengujian A/B yang mudah dengan Firebase Remote Config

Cobalah

Sebelum memulai

  1. Sertakan library ML Kit di Podfile Anda:

    Untuk memaketkan model dengan aplikasi Anda:

    pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
    

    Untuk mendownload model dari Firebase secara dinamis, tambahkan LinkFirebase dependensi:

    pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
    pod 'GoogleMLKit/LinkFirebase', '3.2.0'
    
  2. Setelah menginstal atau mengupdate Pod project, buka project Xcode Anda menggunakan .xcworkspace-nya. ML Kit didukung di Xcode versi 13.2.1 atau yang lebih tinggi.

  3. Jika ingin mendownload model, pastikan Anda menambahkan Firebase ke project iOS, jika Anda belum melakukannya. Hal ini tidak diperlukan jika Anda memaketkan model transformer.

1. Muat model

Mengonfigurasi sumber model lokal

Untuk memaketkan model dengan aplikasi Anda:

  1. Salin file model (biasanya berakhiran .tflite atau .lite) ke Xcode Anda , berhati-hatilah saat memilih Copy bundle resources saat Anda melakukannya. Tujuan file model akan disertakan dalam app bundle dan tersedia untuk ML Kit.

  2. Buat objek LocalModel, dengan menentukan jalur ke file model:

    Swift

    let localModel = LocalModel(path: localModelFilePath)

    Objective-C

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

Mengonfigurasi sumber model yang dihosting Firebase

Untuk menggunakan model yang dihosting dari jarak jauh, buat objek RemoteModel dengan menentukan nama yang Anda berikan pada model saat memublikasikannya:

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];

Kemudian, mulai tugas download model dengan menentukan kondisi yang Anda izinkan untuk diunduh. Jika model tidak ada di perangkat, atau jika model versi baru yang tersedia, tugas ini akan mendownload dari Firebase:

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];

Banyak aplikasi memulai tugas download dalam kode inisialisasinya, tetapi Anda dapat melakukannya kapan saja sebelum Anda perlu menggunakan model.

Mengonfigurasi pemberi label gambar

Setelah sumber model dikonfigurasi, buat objek ImageLabeler dari sumber model tersebut tersebut lebih mendalam.

Tersedia opsi-opsi berikut:

Opsi
confidenceThreshold

Skor keyakinan minimum dari label yang terdeteksi. Jika tidak disetel, batas pengklasifikasi yang ditentukan oleh metadata model akan digunakan. Jika model tidak berisi metadata apa pun atau metadata tidak menentukan ambang batas pengklasifikasi, ambang batas default 0,0 akan data

maxResultCount

Jumlah label maksimum yang akan ditampilkan. Jika tidak disetel, nilai default 10 akan digunakan.

Jika Anda hanya memiliki model yang dipaketkan secara lokal, cukup buat pemberi label dari Objek LocalModel:

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];

Jika Anda memiliki model yang dihosting dari jarak jauh, Anda harus memeriksa apakah model tersebut sudah diunduh sebelum Anda menjalankannya. Anda dapat memeriksa status download model tugas menggunakan metode isModelDownloaded(remoteModel:) pengelola model.

Meskipun Anda hanya perlu mengonfirmasi hal ini sebelum menjalankan pemberi label, jika Anda baik memiliki model yang dihosting dari jarak jauh maupun model yang dipaketkan secara lokal, masuk akal untuk melakukan pemeriksaan ini saat membuat instance ImageLabeler: buat pemberi label dari model jarak jauh jika telah didownload, dan dari model lokal sebaliknya.

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];

Jika hanya memiliki model yang dihosting dari jarak jauh, Anda harus menonaktifkan model lainnya—misalnya, menyamarkan atau menyembunyikan sebagian UI—hingga Anda mengonfirmasi bahwa model telah didownload.

Anda bisa mendapatkan status download model dengan melampirkan observer ke default Pusat Notifikasi. Pastikan untuk menggunakan referensi lemah ke self di observer karena unduhan bisa memakan waktu beberapa saat, dan objek asalnya dapat yang dibebaskan pada saat pengunduhan selesai. Contoh:

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. Menyiapkan gambar input

Buat objek VisionImage menggunakan UIImage atau objek CMSampleBuffer.

Jika Anda menggunakan UIImage, ikuti langkah-langkah berikut:

  • Buat objek VisionImage dengan UIImage. Pastikan untuk menentukan .orientation yang benar.

    Swift

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

    Objective-C

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

Jika Anda menggunakan CMSampleBuffer, ikuti langkah-langkah berikut:

  • Tentukan orientasi data gambar yang terdapat dalam CMSampleBuffer.

    Untuk mendapatkan orientasi gambar:

    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;
      }
    }
          
  • Buat objek VisionImage menggunakan Objek dan orientasi CMSampleBuffer:

    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. Jalankan pemberi label gambar

Untuk memberi label pada objek dalam gambar, teruskan objek image ke metode ImageLabeler Metode process().

Secara asinkron:

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.
     }];

Secara sinkron:

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. Mendapatkan informasi tentang entitas berlabel

Jika operasi pelabelan pada gambar berhasil, array itu akan ImageLabel Setiap ImageLabel mewakili sesuatu yang yang diberi label dalam gambar. Anda bisa mendapatkan deskripsi teks setiap label (jika tersedia di metadata file model TensorFlow Lite), skor keyakinan, dan indeks. Contoh:

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;
}

Tips untuk meningkatkan performa real-time

Jika Anda ingin memberikan label pada gambar dalam aplikasi real-time, ikuti panduan untuk mencapai kecepatan frame terbaik:

  • Untuk memproses frame video, gunakan API sinkron results(in:) dari detektor. Telepon metode ini dari class AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) untuk mendapatkan hasil dari video yang diberikan secara sinkron {i>frame<i}. Simpan AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames sebagai true untuk men-throttle panggilan ke detektor. Jika frame video tersedia saat detektor sedang berjalan, dan frame tersebut akan dihapus.
  • Jika Anda menggunakan output detektor untuk menempatkan grafik gambar input, pertama-tama dapatkan hasilnya dari ML Kit, lalu render gambar dan overlay dalam satu langkah. Dengan demikian, Anda merender ke permukaan tampilan hanya sekali untuk setiap {i> frame<i} input yang diproses. Lihat updatePreviewOverlayViewWithLastFrame dalam contoh panduan memulai ML Kit sebagai contoh.