ติดป้ายกํากับรูปภาพด้วยรูปแบบที่กําหนดเองบน 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 ให้เพิ่มทรัพยากร Dependency 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 จากออบเจ็กต์เหล่านี้

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

ตัวเลือก
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's 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's captureOutput(_, didOutput:from:) เพื่อรับผลลัพธ์จากเฟรมวิดีโอพร้อมกัน เก็บ AVCaptureVideoDataOutput's alwaysDiscardsLateVideoFrames เป็น true เพื่อควบคุมการโทรไปยังตัวตรวจจับ หาก กรอบวิดีโอใหม่พร้อมใช้งานขณะที่ตัวตรวจจับกําลังทํางาน ระบบจะวางกรอบดังกล่าวไว้
  • หากใช้เอาต์พุตของตัวตรวจจับเพื่อวางซ้อนกราฟิกบนรูปภาพอินพุต ให้ดูผลลัพธ์จาก ML Kit ก่อน แล้วแสดงผลรูปภาพและวางซ้อนภายในขั้นตอนเดียว วิธีนี้จะช่วยให้คุณแสดงผลในพื้นที่แสดงผลได้เพียงครั้งเดียวสําหรับเฟรมอินพุตที่ได้รับการประมวลผลแต่ละรายการ ดูตัวอย่างของ update Previewโฆษณาซ้อนทับViewWithLastFrame ได้ในตัวอย่างการเริ่มต้นใช้งาน ML Kit อย่างรวดเร็ว