Mendeteksi, melacak, dan mengklasifikasikan objek dengan model klasifikasi kustom di iOS

Tetap teratur dengan koleksi Simpan dan kategorikan konten berdasarkan preferensi Anda.
Anda dapat menggunakan ML Kit untuk mendeteksi dan melacak objek dalam frame video berturut-turut.

Saat Anda meneruskan gambar ke ML Kit, fitur ini akan mendeteksi hingga lima objek dalam gambar bersama dengan posisi setiap objek dalam gambar. Saat mendeteksi objek dalam streaming video, setiap objek memiliki ID unik yang dapat Anda gunakan untuk melacak objek dari frame ke frame.

Anda dapat menggunakan model klasifikasi gambar kustom untuk mengklasifikasikan objek yang terdeteksi. Lihat Model kustom dengan ML Kit untuk mendapatkan panduan tentang persyaratan kompatibilitas model, tempat untuk 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 Gabungan Model yang Dihosting
Model merupakan bagian dari file .ipa aplikasi, yang akan menambah ukurannya. Model ini bukan bagian dari file .ipa aplikasi Anda. Hosting ini dihosting dengan mengupload ke Firebase Machine Learning.
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 Anda untuk mengupdate model Update model dapat dikirim tanpa memublikasikan ulang aplikasi
Tidak ada pengujian A/B bawaan Pengujian A/B yang mudah dengan Firebase Remote Config

Sebelum memulai

  1. Sertakan library ML Kit di Podfile Anda:

    Untuk memaketkan model dengan aplikasi Anda:

    pod 'GoogleMLKit/ObjectDetectionCustom', '3.2.0'
    

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

    pod 'GoogleMLKit/ObjectDetectionCustom', '3.2.0'
    pod 'GoogleMLKit/LinkFirebase', '3.2.0'
    
  2. Setelah Anda menginstal atau mengupdate Pod project, buka project Xcode 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 belum melakukannya. Langkah ini tidak diperlukan jika Anda memaketkan model.

1. Memuat model

Mengonfigurasi sumber model lokal

Untuk memaketkan model dengan aplikasi:

  1. Salin file model (biasanya diakhiri dengan .tflite atau .lite) ke project Xcode Anda. Berhati-hatilah saat memilih Copy bundle resources ketika Anda melakukannya. File model akan disertakan dalam app bundle dan tersedia untuk ML Kit.

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

    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 CustomRemoteModel, dengan menentukan nama yang diberikan kepada model saat dipublikasikan:

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 inginkan untuk mengizinkan download. Jika model tidak ada di perangkat, atau jika versi model yang lebih baru tersedia, tugas ini akan mendownload model dari Firebase secara asinkron:

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 menggunakan model.

2. Mengonfigurasi detektor objek

Setelah mengonfigurasi sumber model, konfigurasikan detektor objek untuk kasus penggunaan Anda dengan objek CustomObjectDetectorOptions. Anda dapat mengubah setelan berikut:

Setelan Detektor Objek
Mode deteksi STREAM_MODE (default) | SINGLE_IMAGE_MODE

Pada STREAM_MODE (default), detektor objek berjalan dengan latensi yang rendah, tetapi dapat membuat hasil yang tidak lengkap (seperti kotak pembatas atau label kategori yang belum ditetapkan) pada beberapa pemanggilan pertama detektor. Selain itu, pada STREAM_MODE, detektor menetapkan ID pelacakan ke objek, yang dapat Anda gunakan untuk melacak objek lintas frame. Gunakan mode ini saat Anda ingin melacak objek, atau ketika latensi rendah lebih diutamakan, seperti saat memproses streaming video secara real time.

Pada SINGLE_IMAGE_MODE, detektor objek menampilkan hasil setelah kotak pembatas objek ditentukan. Jika Anda juga mengaktifkan klasifikasi, hasil akan ditampilkan setelah kotak pembatas dan label kategori tersedia. Akibatnya, latensi deteksi berpotensi lebih tinggi. Selain itu, pada SINGLE_IMAGE_MODE, ID pelacakan tidak ditetapkan. Gunakan mode ini jika latensi tidak diutamakan dan Anda tidak ingin mendapatkan hasil parsial.

Mendeteksi dan melacak beberapa objek false (default) | true

Mendeteksi dan melacak hingga 5 objek atau hanya objek yang paling tampil beda (default).

Mengklasifikasikan objek false (default) | true

Mengklasifikasikan objek yang terdeteksi atau tidak menggunakan model pengklasifikasi kustom yang diberikan. Untuk menggunakan model klasifikasi kustom, Anda harus menetapkannya ke true.

Nilai minimum keyakinan klasifikasi

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

Label maksimum per objek

Jumlah maksimum label per objek yang akan ditampilkan oleh detektor. Jika tidak disetel, nilai default 10 akan digunakan.

Jika hanya memiliki model yang dipaketkan secara lokal, cukup buat detektor objek dari objek LocalModel:

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;

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

Meskipun Anda hanya perlu mengonfirmasi hal ini sebelum menjalankan detektor objek, jika Anda memiliki model yang dihosting dari jarak jauh dan model yang dipaketkan secara lokal, sebaiknya lakukan pemeriksaan ini saat membuat instance ObjectDetector: buat detektor dari model jarak jauh jika model tersebut sudah didownload, dan dari model lokal jika belum didownload.

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;

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

Anda dapat memperoleh status download model dengan menambahkan observer ke Pusat Notifikasi default. Pastikan untuk menggunakan referensi lemah ke self di blok observer, karena proses download memerlukan waktu beberapa saat, dan objek asalnya dapat dibebaskan pada saat download 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];
            }];

API deteksi dan pelacakan objek dioptimalkan untuk dua kasus penggunaan inti berikut ini:

  • Deteksi langsung dan pelacakan objek paling tampil beda di jendela bidik kamera.
  • Deteksi banyak objek dalam gambar statis.

Untuk mengonfigurasi API bagi kasus penggunaan ini:

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

Buat objek VisionImage menggunakan UIImage atau 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];

4. Membuat dan menjalankan detektor objek

  1. Membuat detektor objek baru:

    Swift

    let objectDetector = ObjectDetector.objectDetector(options: options)

    Objective-C

    MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];
  2. Kemudian, gunakan detektor:

    Secara asinkron:

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

    Secara sinkron:

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

Jika panggilan ke prosesor gambar berhasil, panggilan tersebut akan meneruskan daftar Object ke pengendali penyelesaian atau menampilkan daftar, bergantung pada metode yang digunakan, yaitu asinkron atau sinkron.

Setiap Object berisi properti berikut:

frame CGRect yang menunjukkan posisi objek dalam gambar.
trackingID Bilangan bulat yang mengidentifikasi objek lintas gambar, atau `nil` dalam SINGLE_IMAGE_MODE.
labels
label.text Deskripsi teks label. Hanya ditampilkan jika metadata model TensorFlow Lite berisi deskripsi label.
label.index Indeks label di antara semua label yang didukung oleh pengklasifikasi.
label.confidence Tingkat keyakinan klasifikasi objek.

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

Memastikan pengalaman pengguna yang baik

Untuk mendapatkan pengalaman pengguna terbaik, ikuti panduan berikut di aplikasi Anda:

  • Keberhasilan deteksi objek bergantung pada kompleksitas visual objek. Agar terdeteksi, objek dengan sedikit fitur visual mungkin perlu mengambil sebagian besar gambar. Anda sebaiknya memberikan panduan kepada pengguna tentang menangkap input yang berfungsi baik dengan jenis objek yang ingin Anda deteksi.
  • Saat Anda menggunakan klasifikasi, jika ingin mendeteksi objek yang tidak secara jelas termasuk dalam kategori yang didukung, terapkan penanganan khusus untuk objek yang tidak diketahui.

Selain itu, lihat [aplikasi contoh Desain Material ML Kit][Showcase-link]{: .external} dan koleksi Pola Desain Material untuk fitur yang didukung machine learning.

Meningkatkan performa

Jika ingin menggunakan deteksi objek dalam aplikasi real-time, ikuti pedoman ini untuk mencapai frekuensi frame terbaik:

  • Saat menggunakan mode streaming dalam aplikasi real-time, jangan gunakan beberapa deteksi objek, karena sebagian besar perangkat tidak dapat menghasilkan frekuensi frame yang memadai.

  • Untuk memproses frame video, gunakan API sinkron results(in:) dari detektor. Panggil metode ini dari fungsi captureOutput(_, didOutput:from:) AVCaptureVideoDataOutputSampleBufferDelegate untuk mendapatkan hasil dari frame video tertentu secara sinkron. Simpan alwaysDiscardsLateVideoFrames AVCaptureVideoDataOutput sebagai true untuk membatasi panggilan ke detektor. Jika frame video baru tersedia saat detektor sedang berjalan, frame akan dihapus.
  • Jika menggunakan output detektor untuk menempatkan grafis pada gambar input, pertama-tama dapatkan hasil dari ML Kit, lalu render gambar dan tempatkan grafis dalam satu langkah. Dengan demikian, Anda hanya merender ke permukaan tampilan sekali untuk setiap frame input yang diproses. Lihat updatePreviewOverlayViewWithLastFrame dalam contoh panduan memulai ML Kit untuk mengetahui contohnya.