เมื่อส่งรูปภาพไปยัง ML Kit ระบบจะตรวจจับวัตถุได้สูงสุด 5 รายการในรูปภาพพร้อมกับตำแหน่งของวัตถุแต่ละรายการในรูปภาพ เมื่อตรวจจับวัตถุในสตรีมวิดีโอ วัตถุแต่ละรายการจะมีรหัสที่ไม่ซ้ำกันซึ่งคุณใช้เพื่อติดตามวัตถุจากเฟรมหนึ่งไปยังอีกเฟรมหนึ่งได้
คุณสามารถใช้โมเดลการจัดประเภทรูปภาพที่กำหนดเองเพื่อจัดประเภทวัตถุที่ตรวจพบ โปรดดู โมเดลที่กำหนดเองด้วย ML Kit เพื่อดู คำแนะนำเกี่ยวกับข้อกำหนดด้านความเข้ากันได้ของโมเดล ตำแหน่งที่จะค้นหาโมเดลที่ฝึกไว้ล่วงหน้า และวิธีฝึกโมเดลของคุณเอง
การผสานรวมโมเดลที่กำหนดเองทำได้ 2 วิธี คุณสามารถรวมโมเดลไว้ด้วยกันโดยวางไว้ในโฟลเดอร์ชิ้นงานของแอป หรือดาวน์โหลดแบบไดนามิกจาก Cloud Storage ตารางต่อไปนี้เปรียบเทียบตัวเลือกทั้ง 2 รายการ
| โมเดลที่รวมไว้ด้วยกัน | โมเดลที่โฮสต์ |
|---|---|
โมเดลเป็นส่วนหนึ่งของไฟล์ .ipa ของแอป ซึ่ง
เพิ่มขนาดของไฟล์ |
โมเดลไม่ได้เป็นส่วนหนึ่งของไฟล์ .ipa ของแอป โดยจะโฮสต์ด้วยการอัปโหลดไปยัง Cloud Storage เราขอแนะนำให้ใช้
Cloud Storage สำหรับ
Firebase |
| โมเดลพร้อมใช้งานทันที แม้ว่าอุปกรณ์ Android จะออฟไลน์อยู่ก็ตาม | แอปของคุณต้องมีโค้ดเพื่อดาวน์โหลดโมเดลตามความต้องการ |
| ไม่จำเป็นต้องมีโปรเจ็กต์ Firebase | ต้องมีโปรเจ็กต์ Firebase (หากใช้ Cloud Storage สำหรับ Firebase) |
| คุณต้องเผยแพร่แอปอีกครั้งเพื่ออัปเดตโมเดล | ส่งการอัปเดตโมเดลโดยไม่ต้องเผยแพร่แอปอีกครั้ง |
| ไม่มีการทดสอบ A/B ในตัว | การทดสอบ A/B ด้วย การกำหนดค่าระยะไกลของ Firebase |
ลองเลย
- ดูแอปเริ่มต้นใช้งานด่วนของ Vision เพื่อดูตัวอย่างการใช้งานโมเดลที่รวมไว้ด้วยกัน และ แอปเริ่มต้นใช้งานด่วนของ AutoML เพื่อดู ตัวอย่างการใช้งานโมเดลที่โฮสต์
- ดูแอปตัวอย่าง Material Design เพื่อดูการใช้งาน API นี้แบบครบวงจร
ก่อนเริ่มต้น
ใส่ไลบรารี ML Kit ใน Podfile ดังนี้
pod 'GoogleMLKit/ObjectDetectionCustom', '8.0.0'หลังจากติดตั้งหรืออัปเดต Pods ของโปรเจ็กต์แล้ว ให้เปิดโปรเจ็กต์ Xcode โดยใช้ไฟล์
.xcworkspaceML Kit รองรับใน Xcode เวอร์ชัน 13.2.1 ขึ้นไปหากต้องการดาวน์โหลดโมเดลโดยใช้ Cloud Storage สำหรับ Firebase ให้ ตรวจสอบว่าคุณ ได้เพิ่ม Firebase ลงในโปรเจ็กต์ iOS แล้ว หากยังไม่ได้ดำเนินการ การดำเนินการนี้ไม่จำเป็นเมื่อคุณรวม โมเดลไว้ด้วยกัน
1. โหลดโมเดล
กำหนดค่าแหล่งที่มาของโมเดลในเครื่อง
วิธีรวมโมเดลไว้กับแอป
คัดลอกไฟล์โมเดล (โดยปกติจะลงท้ายด้วย
.tfliteหรือ.lite) ไปยังโปรเจ็กต์ Xcode โดยตรวจสอบว่าได้เลือกCopy bundle resourcesเมื่อดำเนินการ ไฟล์โมเดลจะรวมอยู่ใน App Bundle และพร้อมใช้งานสำหรับ ML Kitสร้างออบเจ็กต์
LocalModelโดยระบุเส้นทางไปยังไฟล์โมเดลSwift
let localModel = LocalModel(path: localModelFilePath)
Objective-C
MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelFilePath];
กำหนดค่าแหล่งที่มาของโมเดลที่โฮสต์จากระยะไกล
หากต้องการใช้โมเดลที่โฮสต์จากระยะไกล คุณต้องดาวน์โหลดไฟล์โมเดลลงในพื้นที่เก็บข้อมูลในเครื่องของอุปกรณ์โดยใช้ตรรกะของแอปเอง แล้วโหลดเป็นโมเดลในเครื่อง เราขอแนะนำให้ใช้ Cloud Storage for Firebase เพื่อโฮสต์โมเดล ดูรายละเอียดการใช้งานได้ที่ คู่มือการย้ายข้อมูลจาก Firebase ML ไปยัง Cloud Storage
2. กำหนดค่าตัวตรวจจับวัตถุ
หลังจากกำหนดค่าแหล่งที่มาของโมเดลแล้ว ให้กำหนดค่าตัวตรวจจับวัตถุสำหรับกรณีการใช้งานของคุณด้วยออบเจ็กต์ CustomObjectDetectorOptions คุณสามารถเปลี่ยนการตั้งค่าต่อไปนี้ได้
| การตั้งค่าตัวตรวจจับวัตถุ | |
|---|---|
| โหมดการตรวจจับ |
STREAM_MODE (ค่าเริ่มต้น) | SINGLE_IMAGE_MODE
ใน ใน |
| ตรวจจับและติดตามวัตถุหลายรายการ |
false (ค่าเริ่มต้น) | true
เลือกว่าจะตรวจจับและติดตามวัตถุได้สูงสุด 5 รายการหรือเฉพาะวัตถุที่โดดเด่นที่สุด (ค่าเริ่มต้น) |
| จัดประเภทวัตถุ |
false (ค่าเริ่มต้น) | true
เลือกว่าจะจัดประเภทวัตถุที่ตรวจพบโดยใช้โมเดลตัวแยกประเภทแบบกำหนดเองที่ให้ไว้หรือไม่ หากต้องการใช้โมเดลการจัดประเภทที่กำหนดเอง
คุณต้องตั้งค่านี้เป็น |
| เกณฑ์ความเชื่อมั่นในการจัดประเภท |
คะแนนความเชื่อมั่นขั้นต่ำของป้ายกำกับที่ตรวจพบ หากไม่ได้ตั้งค่า ระบบจะใช้เกณฑ์ตัวแยกประเภทที่ระบุโดยข้อมูลเมตาของโมเดล หากโมเดลไม่มีข้อมูลเมตาหรือข้อมูลเมตาไม่ได้ ระบุเกณฑ์ตัวแยกประเภท ระบบจะใช้เกณฑ์เริ่มต้นที่ 0.0 |
| ป้ายกำกับสูงสุดต่อวัตถุ |
จำนวนป้ายกำกับสูงสุดต่อวัตถุที่ตัวตรวจจับจะ แสดงผล หากไม่ได้ตั้งค่า ระบบจะใช้ค่าเริ่มต้นที่ 10 |
หากมีเฉพาะโมเดลที่รวมไว้ด้วยกันในเครื่อง ให้สร้างตัวตรวจจับวัตถุจากออบเจ็กต์ 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;
หากมีโมเดลที่โฮสต์จากระยะไกล คุณจะต้องตรวจสอบว่าได้ดาวน์โหลดโมเดลแล้วก่อนที่จะดำเนินการ
แม้ว่าคุณจะต้องยืนยันการดาวน์โหลดโมเดลก่อนที่จะเรียกใช้ตัวตรวจจับวัตถุเท่านั้น แต่หากคุณมีทั้งโมเดลที่โฮสต์จากระยะไกลและโมเดลที่รวมไว้ด้วยกันในเครื่อง การตรวจสอบนี้เมื่อสร้างอินสแตนซ์ ObjectDetector อาจเป็นเรื่องสมเหตุสมผล กล่าวคือ สร้างตัวตรวจจับจากโมเดลระยะไกลหากดาวน์โหลดแล้ว และสร้างจากโมเดลในเครื่องหากยังไม่ได้ดาวน์โหลด
Swift
// Path where your download logic saves the model let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite") let model: LocalModel if FileManager.default.fileExists(atPath: localModelURL.path) { // Use the downloaded model model = LocalModel(path: localModelURL.path) } else { // Fall back to bundled model guard let bundledModelPath = Bundle.main.path(forResource: "model", ofType: "tflite") else { return } model = LocalModel(path: bundledModelPath) } let options = CustomObjectDetectorOptions(localModel: model) options.detectorMode = .singleImage options.shouldEnableClassification = true options.shouldEnableMultipleObjects = true options.classificationConfidenceThreshold = NSNumber(value: 0.5) options.maxPerObjectLabelCount = 3 let objectDetector = ObjectDetector.objectDetector(options: options)
Objective-C
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"]; MLKLocalModel *model; if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) { // Use the downloaded model model = [[MLKLocalModel alloc] initWithPath:localModelPath]; } else { // Fall back to bundled model NSString *bundledModelPath = [NSBundle.mainBundle pathForResource:@"model" ofType:@"tflite"]; model = [[MLKLocalModel alloc] initWithPath:bundledModelPath]; } MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:model]; options.detectorMode = MLKObjectDetectorModeSingleImage; options.shouldEnableClassification = YES; options.shouldEnableMultipleObjects = YES; options.classificationConfidenceThreshold = @(0.5); options.maxPerObjectLabelCount = 3; MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];
หากมีเฉพาะโมเดลที่โฮสต์จากระยะไกล คุณควรปิดใช้ฟังก์ชันการทำงานที่เกี่ยวข้องกับโมเดล เช่น ทำให้ส่วนหนึ่งของ UI เป็นสีเทาหรือซ่อนไว้ จนกว่าจะยืนยันว่าได้ดาวน์โหลดโมเดลแล้ว
Swift
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite") if FileManager.default.fileExists(atPath: localModelURL.path) { // Model is already cached, initialize immediately self.initializeDetector(with: localModelURL) } else { // Model is not yet available, show loading UI and start download self.showLoadingUI() let storage = Storage.storage() let modelRef = storage.reference(forURL: "gs://YOUR_BUCKET/path/to/model.tflite") modelRef.write(toFile: localModelURL) { url, error in self.hideLoadingUI() if let error = error { // Handle download error self.showErrorUI() } else if let modelURL = url { // Download success, initialize detector self.initializeDetector(with: modelURL) } } } func initializeDetector(with modelURL: URL) { let localModel = LocalModel(path: modelURL.path) let options = CustomObjectDetectorOptions(localModel: localModel) options.detectorMode = .singleImage options.shouldEnableClassification = true options.shouldEnableMultipleObjects = true self.objectDetector = ObjectDetector.objectDetector(options: options) // Enable ML features in UI self.enableMLFeatures() }
Objective-C
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"]; NSURL *localModelURL = [NSURL fileURLWithPath:localModelPath]; if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) { // Model is already cached, initialize immediately [self initializeDetectorWithURL:localModelURL]; } else { // Model is not yet available, show loading UI and start download [self showLoadingUI]; FIRStorage *storage = [FIRStorage storage]; FIRStorageReference *modelRef = [storage referenceForURL:@"gs://YOUR_BUCKET/path/to/model.tflite"]; [modelRef writeToFile:localModelURL completion:^(NSURL * _Nullable URL, NSError * _Nullable error) { [self hideLoadingUI]; if (error != nil) { // Handle download error [self showErrorUI]; } else { // Download success, initialize detector [self initializeDetectorWithURL:URL]; } }]; } - (void)initializeDetectorWithURL:(NSURL *)modelURL { MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:modelURL.path]; MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel]; options.detectorMode = MLKObjectDetectorModeSingleImage; options.shouldEnableClassification = YES; options.shouldEnableMultipleObjects = YES; self.objectDetector = [MLKObjectDetector objectDetectorWithOptions:options]; // Enable ML features in UI [self enableMLFeatures]; }
API การตรวจจับและติดตามวัตถุได้รับการปรับให้เหมาะกับกรณีการใช้งานหลัก 2 กรณีต่อไปนี้
- การตรวจจับและติดตามวัตถุที่โดดเด่นที่สุดในช่องมองภาพของกล้องแบบเรียลไทม์
- การตรวจจับวัตถุหลายรายการจากรูปภาพนิ่ง
วิธีกำหนดค่า API สำหรับกรณีการใช้งานเหล่านี้
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. เตรียมรูปภาพอินพุต
สร้างออบเจ็กต์ 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];
4. สร้างและเรียกใช้ตัวตรวจจับวัตถุ
สร้างตัวตรวจจับวัตถุใหม่
Swift
let objectDetector = ObjectDetector.objectDetector(options: options)
Objective-C
MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];
จากนั้นใช้ตัวตรวจจับดังนี้
แบบไม่พร้อมกัน
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. }]; แบบพร้อมกัน
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. ดูข้อมูลเกี่ยวกับวัตถุที่ติดป้ายกำกับ
หากการเรียกใช้หน่วยประมวลผลภาพสำเร็จ ระบบจะส่งรายการ Object ไปยังฟังก์ชัน Completion Handler หรือแสดงผลรายการ ทั้งนี้ขึ้นอยู่กับว่าคุณเรียกใช้เมธอดแบบไม่พร้อมกันหรือแบบพร้อมกัน
Object แต่ละรายการมีพร็อพเพอร์ตี้ต่อไปนี้
frame |
A CGRect ที่ระบุตำแหน่งของวัตถุใน
รูปภาพ |
||||||
trackingID |
จำนวนเต็มที่ระบุวัตถุในรูปภาพ หรือ `nil` ใน SINGLE_IMAGE_MODE | ||||||
labels |
|
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]; } }
การรับประกันประสบการณ์การใช้งานที่ยอดเยี่ยม
เพื่อให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ดีที่สุด ให้ปฏิบัติตามหลักเกณฑ์ต่อไปนี้ในแอป
- การตรวจจับออบเจ็กต์จะสำเร็จหรือไม่ขึ้นอยู่กับความซับซ้อนของภาพวัตถุ วัตถุที่มีฟีเจอร์ภาพจำนวนน้อยอาจต้องใช้พื้นที่ส่วนใหญ่ของรูปภาพจึงจะตรวจพบ คุณควรให้คำแนะนำแก่ผู้ใช้เกี่ยวกับการจับภาพอินพุตที่ทำงานได้ดีกับวัตถุประเภทที่คุณต้องการตรวจจับ
- เมื่อใช้การจัดประเภท หากต้องการตรวจจับวัตถุที่ไม่ได้อยู่ในหมวดหมู่ที่รองรับอย่างชัดเจน ให้ใช้การจัดการพิเศษสำหรับวัตถุที่ไม่รู้จัก
นอกจากนี้ โปรดดู แอปตัวอย่าง ML Kit Material Design และ คอลเล็กชัน รูปแบบ Material Design สำหรับฟีเจอร์ที่ขับเคลื่อนโดยแมชชีนเลิร์นนิง
การปรับปรุงประสิทธิภาพการทำงาน
หากต้องการใช้การตรวจจับออบเจ็กต์ในแอปพลิเคชันแบบเรียลไทม์ ให้ปฏิบัติตามหลักเกณฑ์ต่อไปนี้เพื่อให้ได้อัตราเฟรมที่ดีที่สุดเมื่อใช้โหมดสตรีมมิงในแอปพลิเคชันแบบเรียลไทม์ ให้หลีกเลี่ยงการตรวจจับออบเจ็กต์หลายรายการ เนื่องจากอุปกรณ์ส่วนใหญ่ไม่สามารถสร้างอัตราเฟรมที่เพียงพอได้
- สำหรับการประมวลผลเฟรมวิดีโอ ให้ใช้ API แบบพร้อมกัน
results(in:)ของตัวตรวจจับ เรียกใช้เมธอดนี้จากฟังก์ชันAVCaptureVideoDataOutputSampleBufferDelegateของcaptureOutput(_, didOutput:from:)เพื่อรับผลลัพธ์จากเฟรมวิดีโอที่ระบุแบบพร้อมกัน ตั้งค่าAVCaptureVideoDataOutputของalwaysDiscardsLateVideoFramesเป็นtrueเพื่อควบคุมการเรียกใช้ตัวตรวจจับ หากเฟรมวิดีโอใหม่ พร้อมใช้งานขณะที่ตัวตรวจจับกำลังทำงาน ระบบจะทิ้งเฟรมนั้น - หากใช้เอาต์พุตของตัวตรวจจับเพื่อซ้อนทับกราฟิกบน รูปภาพอินพุต ให้รับผลลัพธ์จาก ML Kit ก่อน แล้วจึงแสดงรูปภาพ และซ้อนทับในขั้นตอนเดียว การทำเช่นนี้จะทำให้คุณแสดงผลไปยังพื้นผิวการแสดงผล เพียงครั้งเดียวสำหรับเฟรมอินพุตที่ประมวลผลแต่ละเฟรม ดูตัวอย่างได้ที่ updatePreviewOverlayViewWithLastFrame ในตัวอย่างเริ่มต้นใช้งานด่วนของ ML Kit