在 iOS 上使用自訂模型為圖片加上標籤

您可以使用 ML Kit 辨識圖片中的實體,並加上標籤。 這個 API 支援多種自訂圖片分類模型。請 相關指南請參閱「使用 ML Kit 自訂模型」一文 模型相容性需求,哪裡可以找到預先訓練模型 以及如何訓練自有模型

整合自訂模型的方式有兩種。您可以將模型分門別類 將檔案放入應用程式的素材資源資料夾,或者可以透過動態方式下載 。下表比較這兩種選項。

套裝組合模型 託管模型
這個模型是應用程式 APK 的一部分,會增加其大小。 這個模型並非 APK 的一部分。這是由上傳至 Firebase 機器學習
可立即使用型號,即使 Android 裝置離線也沒問題 模型會隨選下載
不需要 Firebase 專案 需要 Firebase 專案
您必須重新發布應用程式才能更新模型 不必重新發布應用程式即可推送模型更新
沒有內建 A/B 測試 使用 Firebase 遠端設定輕鬆進行 A/B 測試

立即試用

事前準備

  1. 在 Podfile 中加入 ML Kit 程式庫:

    將模型與應用程式綁定:

    pod 'GoogleMLKit/ImageLabelingCustom', '15.5.0'
    

    如要從 Firebase 動態下載模型,請新增 LinkFirebase 依附元件:

    pod 'GoogleMLKit/ImageLabelingCustom', '15.5.0'
    pod 'GoogleMLKit/LinkFirebase', '15.5.0'
    
  2. 安裝或更新專案的 Pod 後,請開啟 Xcode 專案 使用 .xcworkspace。Xcode 13.2.1 版支援 ML Kit 或更高版本。

  3. 如要下載模型,請務必 將 Firebase 加進您的 iOS 專案, 如果尚未建立如果您將 模型

1. 載入模型

設定本機模型來源

將模型與應用程式組合如下:

  1. 將模型檔案 (通常結尾為 .tflite.lite) 複製到 Xcode 專案時,請務必選取 Copy bundle resources。 模型檔案就會包含在應用程式套件中,並可供 ML Kit 使用。

  2. 建立 LocalModel 物件,指定模型檔案的路徑:

    Swift

    let localModel = LocalModel(path: localModelFilePath)

    Objective-C

    MLKLocalModel *localModel =
        [[MLKLocalModel alloc] initWithPath:localModelFilePath];
,瞭解如何調查及移除這項存取權。

設定 Firebase 託管的模型來源

如要使用遠端託管的模型,請建立 RemoteModel 物件並指定 命名:

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

接著,啟動模型下載工作,並指定在 您要允許下載的應用程式。如果裝置上沒有該型號,或者是新型號 就能以非同步方式下載該模型 建立 Vertex AI 模型

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

許多應用程式會在初始化程式碼中啟動下載工作,但您 這個模型會在您需要使用模型前執行

設定圖片標籤人員

設定模型來源後,請從該模型建立 ImageLabeler 物件 我們很快就會深入探討 所以目前先概略介紹

可用選項如下所示:

選項
confidenceThreshold

偵測到標籤的最低可信度分數。如果未設定 系統會使用模型中繼資料指定的分類器門檻。 如果模型未包含任何中繼資料,或中繼資料不包含 指定分類器門檻,預設門檻為 0.0

maxResultCount

要傳回的標籤數量上限。如果未設定,系統會採用預設值 將使用 10。

如果您只有本機組合模型,只要從 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];

如果您使用的是遠端託管的模型,則須檢查該模型是否已 執行前已下載完成您可以查看模型下載狀態 工作使用模型管理員的 isModelDownloaded(remoteModel:) 方法。

雖然您不必在執行標籤人員前確認 同時擁有遠端託管和本機封裝模型 要在將 ImageLabeler 例項化時執行這項檢查:請建立 下載自遠端模型和本機模型的標籤人員 反之。

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

如果只有遠端託管的模型,請停用模型相關 功能,例如顯示為灰色或隱藏部分 UI,直到 您確認模型已下載完成

您可以將觀察器附加至預設值,取得模型下載狀態 通知中心。請務必在觀察器中對 self 使用較弱的參照 因此,下載作業可能需要一些時間,而且原始物件可 下載完成後就會釋出空間。例如:

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. 準備輸入圖片

使用 UIImageVisionImage CMSampleBuffer

如果您使用 UIImage,請按照下列步驟操作:

  • 使用 UIImage 建立 VisionImage 物件。請務必指定正確的 .orientation

    Swift

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

    Objective-C

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

如果您使用 CMSampleBuffer,請按照下列步驟操作:

  • 指定 CMSampleBuffer

    如何取得圖片方向:

    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;
      }
    }
          
  • 使用VisionImage 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. 執行映像檔標籤工具

如要為圖片中的物件加上標籤,請將 image 物件傳遞至 ImageLabelerprocess() 方法。

非同步:

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

同步:

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. 取得已加上標籤實體的相關資訊

如果圖片標籤作業成功,則會傳回 ImageLabel。每個 ImageLabel 都代表 映像檔和映像檔版本您可以取得每個標籤的文字說明 (如果可以使用 TensorFlow Lite 模型檔案的中繼資料)、可信度分數和索引。 例如:

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

即時效能改善訣竅

如要在即時應用程式中為圖片加上標籤,請按照下列步驟操作: 實現最佳影格速率: