iOS 物件偵測指南

物件偵測工具工作可讓您偵測多個物件類別是否存在,以及其位置。舉例來說,物件偵測工具可以找出圖片中的狗。以下操作說明將說明如何在 iOS 中使用物件偵測器工作。您可以在 GitHub 取得這些操作說明中提及的程式碼範例。

如要查看這項工作的實際運作情形,請參閱此網路示範。如要進一步瞭解這項工作的功能、模型和設定選項,請參閱總覽

程式碼範例

MediaPipe Tasks 範例程式碼是 iOS 版物件偵測工具應用程式的基本實作。這個範例使用實體 iOS 裝置上的相機持續偵測物件,也能使用裝置庫中的圖片和影片,以靜態方式偵測物件。

您可以將該應用程式做為建構自己的 iOS 應用程式的基礎,或在修改現有應用程式時參照。物件偵測工具範例程式碼由 GitHub 代管。

下載程式碼

以下操作說明說明如何使用 git 指令列工具建立範例程式碼的本機副本。

如要下載範例程式碼,請按照下列步驟操作:

  1. 使用下列指令複製 Git 存放區:

    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. 您可以選擇將 git 執行個體設為使用稀疏檢查,以便只有物件偵測工具範例應用程式的檔案:

    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/object_detection/ios/
    

建立範例程式碼的本機版本後,可以安裝 MediaPipe 工作程式庫,使用 Xcode 開啟專案並執行應用程式。如需操作說明,請參閱 iOS 設定指南

重要元件

下列檔案包含物件偵測工具範例應用程式的重要程式碼:

設定

本節說明設定開發環境及程式碼專案以使用物件偵測工具的重要步驟。如需瞭解如何設定開發環境以使用 MediaPipe 工作 (包括平台版本需求),請參閱「iOS 設定指南」。

依附元件

物件偵測工具會使用 MediaPipeTasksVision 程式庫,因此您必須使用 CocoaPods 安裝這個程式庫。這個程式庫與 Swift 和 Objective-C 應用程式相容,不需要任何其他語言的特定設定。

如需在 macOS 上安裝 CocoaPods 的操作說明,請參閱 CocoaPods 安裝指南。 如要瞭解如何建立具有應用程式必要 Pod 的 Podfile,請參閱「使用 CocoaPods」。

使用下列程式碼,在 Podfile 中新增 MediaPipeTasksVision Pod:

target 'MyObjectDetectorApp' do
  use_frameworks!
  pod 'MediaPipeTasksVision'
end

如果您的應用程式含有單元測試目標,請參閱 iOS 設定指南,進一步瞭解如何設定 Podfile

型號

MediaPipe 物件偵測工具工作需要與這項工作相容的已訓練模型。如要進一步瞭解物件偵測工具的可用已訓練模型,請參閱工作總覽「模型」一節

選取並下載模型,然後使用 Xcode 將其新增至專案目錄。 如需將檔案新增至 Xcode 專案的操作說明,請參閱「管理 Xcode 專案中的檔案和資料夾」。

使用 BaseOptions.modelAssetPath 屬性指定應用程式套件中的模型路徑。如需程式碼範例,請參閱下一節。

建立工作

如要建立物件偵測工具工作,請呼叫其中一個初始化器。ObjectDetector(options:) 初始化器會為設定選項設定值,包括執行模式、顯示名稱語言代碼、結果數量上限、可信度門檻、類別許可清單和拒絕清單。

如果您不需要使用自訂設定選項初始化的物件偵測工具,可以使用 ObjectDetector(modelPath:) 初始化器,以預設選項建立物件偵測工具。如要進一步瞭解設定選項,請參閱「設定總覽」。

物件偵測工具工作支援 3 種輸入資料類型:靜態圖片、影片檔案和即時影片串流。根據預設,ObjectDetector(modelPath:) 會初始化靜態圖片的工作。如果想將工作初始化,以便處理影片檔案或直播影片串流,請使用 ObjectDetector(options:) 指定影片或直播執行模式。直播模式也需要額外的 objectDetectorLiveStreamDelegate 設定選項,能夠讓物件偵測工具以非同步方式將偵測結果傳送給委派代表。

請選擇與執行模式對應的分頁,瞭解如何建立工作並執行推論。

Swift

圖片

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = ObjectDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .image
options.maxResults = 5

let objectDetector = try ObjectDetector(options: options)
    

影片

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = ObjectDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video
options.maxResults = 5

let objectDetector = try ObjectDetector(options: options)
    

直播

import MediaPipeTasksVision

// Class that conforms to the `ObjectDetectorLiveStreamDelegate` protocol and
// implements the method that the object detector calls once it
// finishes performing detection on each input frame.
class ObjectDetectorResultProcessor: NSObject, ObjectDetectorLiveStreamDelegate {

  func objectDetector(
    _ objectDetector: ObjectDetector,
    didFinishDetection objectDetectionResult: ObjectDetectorResult?,
    timestampInMilliseconds: Int,
    error: Error?) {
    // Process the detection result or errors here.
  }
}

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = ObjectDetectorOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream
options.maxResults = 5

// Assign an object of the class to the `objectDetectorLiveStreamDelegate`
// property.
let processor = ObjectDetectorResultProcessor()
options.objectDetectorLiveStreamDelegate = processor

let objectDetector = try ObjectDetector(options: options)
    

Objective-C

圖片

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPObjectDetectorOptions *options = [[MPPObjectDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;
options.maxResults = 5;

MPPObjectDetector *objectDetector =
      [[MPPObjectDetector alloc] initWithOptions:options error:nil];
    

影片

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPObjectDetectorOptions *options = [[MPPObjectDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;
options.maxResults = 5;

MPPObjectDetector *objectDetector =
      [[MPPObjectDetector alloc] initWithOptions:options error:nil];
    

直播

@import MediaPipeTasksVision;

// Class that conforms to the `ObjectDetectorLiveStreamDelegate` protocol and
// implements the method that the object detector calls once it
// finishes performing detection on each input frame.

@interface APPObjectDetectorResultProcessor : NSObject 

@end

@implementation MPPObjectDetectorResultProcessor

-   (void)objectDetector:(MPPObjectDetector *)objectDetector
    didFinishDetectionWithResult:(MPPObjectDetectorResult *)ObjectDetectorResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the detection result or errors here.

}

@end

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPObjectDetectorOptions *options = [[MPPObjectDetectorOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;
options.maxResults = 5;

// Assign an object of the class to the `objectDetectorLiveStreamDelegate`
// property.
APPObjectDetectorResultProcessor *processor = [APPObjectDetectorResultProcessor new];
options.objectDetectorLiveStreamDelegate = processor;

MPPObjectDetector *objectDetector =
      [[MPPObjectDetector alloc] initWithOptions:options error:nil];
    

設定選項

這項工作的 iOS 應用程式設定選項如下:

選項名稱 說明 值範圍 預設值
runningMode 設定工作的執行模式。共有三種模式:

IMAGE:單一圖片輸入的模式。

影片:影片已解碼影格的模式。

LIVE_STREAM:輸入資料串流 (例如攝影機) 的直播模式。在這個模式下,必須呼叫 resultListener 才能設定事件監聽器,以非同步方式接收結果。
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
displayNamesLocales 設定標籤語言,用於工作模型中繼資料內的顯示名稱 (如有)。英文的預設值是 en。您可以使用 TensorFlow Lite Metadata Writer API,在自訂模型的中繼資料中加入本地化標籤。 語言代碼 en
maxResults 設定要傳回的最高分數偵測結果數量上限 (選用)。 任何正數 -1 (傳回所有結果)
scoreThreshold 設定預測分數門檻,覆寫模型中繼資料 (如有) 中提供的分數門檻。這個值下方的結果遭到拒絕。 不限浮點值 未設定
categoryAllowlist 設定允許的類別名稱 (選用)。如果不是空白,則系統會篩除類別名稱不在這個組合中的偵測結果。系統會忽略重複或不明的類別名稱。這個選項與 categoryDenylist 互斥,且同時使用兩者會導致錯誤。 任何字串 未設定
categoryDenylist 設定不允許使用的類別名稱清單。如果非空白,系統會篩除類別名稱在此集合中的偵測結果。系統會忽略重複或不明的類別名稱。這個選項與 categoryAllowlist 互斥,且同時使用兩者會導致錯誤。 任何字串 未設定

直播設定

執行模式設為直播時,物件偵測工具需要額外的 objectDetectorLiveStreamDelegate 設定選項,可讓偵測工具以非同步的方式提供偵測結果。委派項目會實作 objectDetector(_objectDetector:didFinishDetection:timestampInMilliseconds:error:) 方法,物件偵測工具會在處理每個影格的偵測結果後呼叫此方法。

選項名稱 說明 值範圍 預設值
objectDetectorLiveStreamDelegate 啟用物件偵測工具,在直播模式下以非同步的方式接收偵測結果。執行個體設為此屬性的類別必須實作 objectDetector(_:didFinishDetection:timestampInMilliseconds:error:) 方法。 不適用 未設定

準備資料

您必須先將輸入圖片或框架轉換為 MPImage 物件,才能將其傳送至物件偵測工具。MPImage 支援不同類型的 iOS 圖片格式,且可在任何執行模式下用於推論。如要進一步瞭解 MPImage,請參閱 MPImage API

依據您的用途和應用程式所需的執行模式選擇 iOS 圖片格式。MPImage 接受 UIImageCVPixelBufferCMSampleBuffer iOS 圖片格式。

UIImage

UIImage 格式非常適合下列執行模式:

  • 圖片:應用程式套件、使用者圖片庫或檔案系統格式的圖片,可以轉換為 MPImage 物件。UIImage

  • 影片:使用 AVAssetImageGenerator 將影片影格擷取為 CGImage 格式,然後轉換為 UIImage 圖片。

Swift

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(uiImage: image)
    

Objective-C

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

這個範例會使用預設的 UIImage.Orientation.Up 方向初始化 MPImage。您可以使用任何支援的 UIImage.Orientation 值初始化 MPImage。物件偵測工具不支援鏡像方向,例如 .upMirrored.downMirrored.leftMirrored.rightMirrored

如要進一步瞭解 UIImage,請參閱「UIImage Apple Developer 說明文件」。

CVPixelBuffer

CVPixelBuffer 格式非常適合產生影格以及使用 iOS CoreImage 架構處理的應用程式。

CVPixelBuffer 格式非常適合下列執行模式:

  • 圖片:在使用 iOS 的 CoreImage 架構進行某些處理後產生 CVPixelBuffer 圖片的應用程式,可透過圖片執行模式傳送至物件偵測工具。

  • 影片:您可以將影片影格轉換為 CVPixelBuffer 格式進行處理,然後在影片模式中傳送至物件偵測工具。

  • 直播:使用 iOS 相機產生影格的應用程式可能會先轉換為 CVPixelBuffer 格式進行處理,再傳送至直播模式下的物件偵測工具。

Swift

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(pixelBuffer: pixelBuffer)
    

Objective-C

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

如要進一步瞭解 CVPixelBuffer,請參閱 CVPixelBuffer Apple 開發人員說明文件

CMSampleBuffer

CMSampleBuffer 格式可儲存統一媒體類型的媒體樣本,非常適合用於直播執行模式。iOS 相機的即時影格會由 iOS AVCaptureVideoDataOutputCMSampleBuffer 格式非同步傳送。

Swift

// Obtain a CMSampleBuffer.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(sampleBuffer: sampleBuffer)
    

Objective-C

// Obtain a `CMSampleBuffer`.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
    

如要進一步瞭解 CMSampleBuffer,請參閱 CMSampleBuffer Apple 開發人員說明文件

執行工作

如要執行物件偵測工具,請使用已指派的執行模式專屬的 detect() 方法:

  • 靜態圖片:detect(image:)
  • 影片:《detect(videoFrame:timestampInMilliseconds:)
  • 直播:detectAsync(image:)

以下程式碼範例顯示如何在這些不同的執行模式下,執行物件偵測工具的基本範例:

Swift

圖片

let objectDetector.detect(image:image)
    

影片

let objectDetector.detect(videoFrame:image)
    

直播

let objectDetector.detectAsync(image:image)
    

Objective-C

圖片

MPPObjectDetectorResult *result = [objectDetector detectInImage:image error:nil];
    

影片

MPPObjectDetectorResult *result = [objectDetector detectInVideoFrame:image          timestampInMilliseconds:timestamp error:nil];
    

直播

BOOL success = [objectDetector detectAsyncInImage:image
                          timestampInMilliseconds:timestamp
                                            error:nil];
    

物件偵測工具程式碼範例會顯示 detect(image:)detect(videoFrame:)detectAsync(image:) 這些模式的實作內容。範例程式碼可讓使用者切換不同的處理模式,但您的用途可能不需要採用這種模式。

注意事項:

  • 以影片模式或直播模式執行時,您必須在物件偵測工具工作中提供輸入影格的時間戳記。

  • 以圖片或影片模式執行時,物件偵測器工作會封鎖目前的執行緒,直到完成輸入圖片或影格的處理作業為止。為避免封鎖目前的執行緒,請使用 iOS DispatchNSOperation 架構在背景執行緒中執行處理作業。

  • 以直播模式執行時,物件偵測器工作會立即傳回,且不會封鎖目前的執行緒。會在處理每個輸入影格後,使用偵測結果叫用 objectDetector(_objectDetector:didFinishDetection:timestampInMilliseconds:error:) 方法。物件偵測工具會在專屬的序列分派佇列上,以非同步方式叫用這個方法。如要在使用者介面上顯示結果,請在處理結果後將結果分派到主佇列。如果在物件偵測工具工作忙於處理其他影格時呼叫 detectAsync 函式,物件偵測工具會忽略新的輸入影格。

處理並顯示結果

執行推論時,物件偵測工具工作會傳回 ObjectDetectorResult 物件,說明在輸入圖片中找到的物件。

以下為這項工作的輸出資料範例:

ObjectDetectorResult:
 Detection #0:
  Box: (x: 355, y: 133, w: 190, h: 206)
  Categories:
   index       : 17
   score       : 0.73828
   class name  : dog
 Detection #1:
  Box: (x: 103, y: 15, w: 138, h: 369)
  Categories:
   index       : 17
   score       : 0.73047
   class name  : dog

下圖以視覺化方式呈現工作輸出內容:

物件偵測工具範例程式碼示範如何顯示從工作傳回的偵測結果,詳情請參閱程式碼範例