ติดป้ายกำกับรูปภาพด้วยรูปแบบที่กำหนดเองใน iOS

คุณสามารถใช้ ML Kit เพื่อจดจำเอนทิตีในรูปภาพและติดป้ายกำกับรายการดังกล่าว API นี้รองรับโมเดลการจัดประเภทรูปภาพที่กำหนดเองหลากหลายรูปแบบ โปรด โปรดดูที่โมเดลที่กำหนดเองด้วย ML Kit เพื่อดูคำแนะนำเกี่ยวกับ ข้อกำหนดความเข้ากันได้กับโมเดล วิธีค้นหาโมเดลก่อนการฝึก และวิธีฝึกโมเดลของคุณเอง

มี 2 วิธีในการรวมโมเดลที่กำหนดเอง คุณสามารถรวมกลุ่มโมเดลได้โดย ใส่ลงในโฟลเดอร์เนื้อหาของแอป หรือคุณจะดาวน์โหลดแบบไดนามิกก็ได้ จาก Firebase ตารางต่อไปนี้จะเปรียบเทียบทั้ง 2 ตัวเลือก

โมเดลแบบกลุ่ม โมเดลที่โฮสต์
โมเดลนี้เป็นส่วนหนึ่งของ APK ของแอป ซึ่งจะเพิ่มขนาด โมเดลนี้ไม่ได้เป็นส่วนหนึ่งของ APK ของคุณ ซึ่งโฮสต์โดยการอัปโหลดไปยัง แมชชีนเลิร์นนิงของ Firebase
โมเดลดังกล่าวจะพร้อมใช้งานทันที แม้ว่าอุปกรณ์ Android จะออฟไลน์อยู่ โมเดลจะดาวน์โหลดแบบออนดีมานด์
ไม่จำเป็นต้องมีโปรเจ็กต์ Firebase ต้องมีโปรเจ็กต์ Firebase
คุณต้องเผยแพร่แอปอีกครั้งเพื่ออัปเดตโมเดล พุชการอัปเดตโมเดลโดยไม่เผยแพร่แอปซ้ำ
ไม่มีการทดสอบ A/B ในตัว การทดสอบ A/B ที่ง่ายดายด้วยการกำหนดค่าระยะไกลของ Firebase

ลองเลย

ก่อนเริ่มต้น

  1. รวมไลบรารี ML Kit ไว้ใน Podfile ดังนี้

    สำหรับการรวมโมเดลกับแอป ให้ทำดังนี้

    pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
    

    สำหรับการดาวน์โหลดโมเดลแบบไดนามิกจาก Firebase ให้เพิ่ม LinkFirebase การพึ่งพา:

    pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
    pod 'GoogleMLKit/LinkFirebase', '3.2.0'
    
  2. หลังจากติดตั้งหรืออัปเดตพ็อดของโปรเจ็กต์แล้ว ให้เปิดโปรเจ็กต์ Xcode โดยใช้ .xcworkspace รองรับ ML Kit ใน Xcode เวอร์ชัน 13.2.1 หรือสูงกว่า

  3. หากต้องการดาวน์โหลดโมเดล โปรดตรวจสอบว่า เพิ่ม Firebase ลงในโปรเจ็กต์ iOS หากคุณยังไม่ได้ดำเนินการ ไม่จำเป็นต้องทำขั้นตอนนี้เมื่อคุณรวมชุด โมเดล

1. โหลดโมเดล

กำหนดค่าต้นทางของโมเดลในเครื่อง

วิธีการรวมโมเดลกับแอปมีดังนี้

  1. คัดลอกไฟล์โมเดล (โดยปกติจะลงท้ายด้วย .tflite หรือ .lite) ไปยัง Xcode ให้เลือก Copy bundle resources เมื่อคุณดำเนินการดังกล่าว ไฟล์โมเดลจะรวมอยู่ใน App Bundle และพร้อมใช้งานสำหรับ 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];

จากนั้นเริ่มงานดาวน์โหลดโมเดล โดยระบุเงื่อนไขที่ ที่คุณต้องการอนุญาตให้ดาวน์โหลด หากไม่มีรุ่นนี้อยู่ในอุปกรณ์ หรือรุ่นที่ใหม่กว่า ของโมเดลพร้อมใช้งาน งานจะดาวน์โหลด จาก 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];

แอปจำนวนมากเริ่มงานดาวน์โหลดในโค้ดเริ่มต้น แต่คุณ จากนั้นคุณจะสามารถทำได้ทุกเมื่อก่อนที่จะต้องใช้โมเดลนี้

กำหนดค่าเครื่องมือติดป้ายกำกับรูปภาพ

หลังจากกำหนดค่าแหล่งที่มาของโมเดลแล้ว ให้สร้างออบเจ็กต์ ImageLabeler จาก 1 รายการ ทั้งหมด

โดยมีตัวเลือกดังต่อไปนี้

ตัวเลือก
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. เตรียมรูปภาพอินพุต

สร้างออบเจ็กต์ VisionImage โดยใช้ UIImage หรือ CMSampleBuffer

หากคุณใช้ UIImage ให้ทำตามขั้นตอนต่อไปนี้

  • สร้างออบเจ็กต์ VisionImage ด้วย UIImage ตรวจสอบว่าได้ระบุ .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 ไปยังออบเจ็กต์ของ ImageLabeler process() วิธี

ไม่พร้อมกัน:

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

เคล็ดลับในการปรับปรุงประสิทธิภาพแบบเรียลไทม์

หากต้องการติดป้ายกำกับรูปภาพในแอปพลิเคชันแบบเรียลไทม์ ให้ทำตามดังนี้ เพื่อให้ได้อัตราเฟรมที่ดีที่สุด

  • สำหรับการประมวลผลเฟรมวิดีโอ ให้ใช้ API แบบซิงโครนัสของ results(in:) ในตัวตรวจจับ โทร เมธอดนี้จาก ของ AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) เพื่อให้ได้ผลลัพธ์จากวิดีโอที่ระบุแบบพร้อมกัน เฟรม เก็บ ของ AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames เป็น true เพื่อควบคุมการโทรหาตัวตรวจจับ หาก เฟรมวิดีโอจะพร้อมใช้งานขณะที่ตัวตรวจจับทำงานอยู่ เฟรมนั้นจะหายไป
  • หากคุณใช้เอาต์พุตของเครื่องมือตรวจจับเพื่อวางซ้อนกราฟิก รูปภาพอินพุต รับผลลัพธ์จาก ML Kit ก่อน จากนั้นจึงแสดงผลรูปภาพ ซ้อนทับในขั้นตอนเดียว การทำเช่นนี้จะช่วยให้แสดงผลบนพื้นผิวจอแสดงผล เพียงครั้งเดียวสำหรับแต่ละเฟรมอินพุตที่ประมวลผลแล้ว ดู updatePreviewOverlayViewWithLastFrame ในตัวอย่างการเริ่มต้นอย่างรวดเร็วใน ML Kit