אפשר להשתמש ב-ML Kit כדי לזהות ברקודים ולפענח אותם.
רוצה לנסות?
- מומלץ לשחק עם האפליקציה לדוגמה כדי .
לפני שמתחילים
- כוללים ב-Podfile את רצפי ה-ML Kit הבאים:
pod 'GoogleMLKit/BarcodeScanning', '15.5.0'
- אחרי שמתקינים או מעדכנים את קבוצות ה-Pod של הפרויקט, פותחים את פרויקט Xcode באמצעות
.xcworkspace
יש תמיכה ב-ML Kit ב-Xcode מגרסה 12.4 ואילך.
הנחיות להוספת תמונה
-
כדי ש-ML Kit יוכל לקרוא ברקודים באופן מדויק, תמונות הקלט חייבות להכיל ברקודים שמיוצגים על ידי כמות מספקת של נתוני פיקסלים.
הדרישות הספציפיות לנתוני פיקסלים תלויות גם בסוג של את הברקוד ואת כמות הנתונים שמקודדים בו, מאחר שברקודים רבים תומכים במטען ייעודי (payload) בגודל משתנה. באופן כללי, המשמעות של הברקוד צריכה להיות ברוחב של 2 פיקסלים לפחות. קודים דו-ממדיים, גובה של 2 פיקסלים.
לדוגמה, ברקודים מסוג EAN-13 מורכבים מעמודות ומרווחים שהם 1, רוחב של 2, 3 או 4 יחידות, כך שתמונת ברקוד מסוג EAN-13 באופן אידיאלי כוללת פסים רווחים ברוחב 2, 4, 6 ו-8 פיקסלים לפחות. מאחר שתקן EAN-13 הברקוד הוא ברוחב 95 יחידות. הוא צריך להיות לפחות 190 יחידות פיקסלים לרוחב.
בפורמטים צפופים יותר, כמו PDF417, נדרשים מידות פיקסלים גבוהות יותר ML Kit כדי לקרוא אותם בצורה אמינה. לדוגמה, קוד PDF417 יכול להכיל עד 34 "מילים" ברוחב של 17 יחידות בשורה אחת, ורצוי שהוא יהיה רוחב של 1156 פיקסלים.
-
מיקוד תמונה לא טוב יכול להשפיע על רמת הדיוק של הסריקה. אם האפליקציה לא מקבלת נתונים תוצאות קבילות, בקשו מהמשתמש לצלם מחדש את התמונה.
-
באפליקציות טיפוסיות מומלץ לספק ערך גבוה יותר היא תמונה ברזולוציה של 1280x720 או 1920x1080, שהופכת ברקודים. שאפשר לסרוק אותו ממרחק גדול יותר מהמצלמה.
עם זאת, באפליקציות שבהן זמן האחזור קריטי, ניתן לשפר צילום תמונות ברזולוציה נמוכה יותר, אבל נדרש הברקוד מהווה את רוב תמונת הקלט. ראו גם טיפים לשיפור הביצועים בזמן אמת.
1. הגדרת סורק הברקוד
אם ידוע לך אילו פורמטים של ברקוד היית רוצה לקרוא, אפשר להאיץ את התהליך של סורק הברקוד על ידי הגדרתו כך שיסרוק רק את הפורמטים האלה.לדוגמה, כדי לסרוק רק קוד אצטקי וקודי QR,
באובייקט BarcodeScannerOptions
, כמו
בדוגמה הבאה:
Swift
let format = .all let barcodeOptions = BarcodeScannerOptions(formats: format)
הפורמטים הבאים נתמכים:
- code128
- code39
- code93
- codaBar
- dataMatrix
- EAN13
- EAN8
- ITF
- qrCode
- UPCA
- UPCE
- PDF417
- Aztec
Objective-C
MLKBarcodeScannerOptions *options = [[MLKBarcodeScannerOptions alloc] initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];
הפורמטים הבאים נתמכים:
- קוד-128 (
MLKBarcodeFormatCode128
) - קוד-39 (
MLKBarcodeFormatCode39
) - קוד-93 (
MLKBarcodeFormatCode93
) - Codabar (
MLKBarcodeFormatCodaBar
) - מטריצת נתונים (
MLKBarcodeFormatDataMatrix
) - EAN-13 (
MLKBarcodeFormatEAN13
) - EAN-8 (
MLKBarcodeFormatEAN8
) - ITF (
MLKBarcodeFormatITF
) - קוד QR (
MLKBarcodeFormatQRCode
) - UPC-A (
MLKBarcodeFormatUPCA
) - UPC-E (
MLKBarcodeFormatUPCE
) - PDF-417 (
MLKBarcodeFormatPDF417
) - קוד אצטקי (
MLKBarcodeFormatAztec
)
2. הכנת תמונת הקלט
כדי לסרוק ברקודים בתמונה, מעבירים את התמונה כ-UIImage
או
CMSampleBufferRef
ל-process()
או ל-results(in:)
של BarcodeScanner
method:
יצירת אובייקט 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. קבלת מופע של BarcodeScanner
מקבלים מופע שלBarcodeScanner
:
Swift
let barcodeScanner = BarcodeScanner.barcodeScanner() // Or, to change the default settings: // let barcodeScanner = BarcodeScanner.barcodeScanner(options: barcodeOptions)
Objective-C
MLKBarcodeScanner *barcodeScanner = [MLKBarcodeScanner barcodeScanner]; // Or, to change the default settings: // MLKBarcodeScanner *barcodeScanner = // [MLKBarcodeScanner barcodeScannerWithOptions:options];
4. עיבוד התמונה
לאחר מכן, מעבירים את התמונה ל-methodprocess()
:
Swift
barcodeScanner.process(visionImage) { features, error in guard error == nil, let features = features, !features.isEmpty else { // Error handling return } // Recognized barcodes }
Objective-C
[barcodeScanner processImage:image completion:^(NSArray<MLKBarcode *> *_Nullable barcodes, NSError *_Nullable error) { if (error != nil) { // Error handling return; } if (barcodes.count > 0) { // Recognized barcodes } }];
5. קבלת מידע מברקודים
אם פעולת סריקת הברקוד מצליחה, הסורק מחזיר מערך שלBarcode
אובייקטים. כל אובייקט Barcode
מייצג
הברקוד שזוהה בתמונה. לכל ברקוד אפשר לראות
וגם את הקואורדינטות התוחמות בתמונת הקלט, וגם את הנתונים הגולמיים המקודדים על ידי
ברקוד. כמו כן, אם סורק הברקוד הצליח לזהות את סוג הנתונים
שמקודדים לפי הברקוד, אפשר לקבל אובייקט שמכיל נתונים שנותחו.
לדוגמה:
Swift
for barcode in barcodes { let corners = barcode.cornerPoints let displayValue = barcode.displayValue let rawValue = barcode.rawValue let valueType = barcode.valueType switch valueType { case .wiFi: let ssid = barcode.wifi?.ssid let password = barcode.wifi?.password let encryptionType = barcode.wifi?.type case .URL: let title = barcode.url!.title let url = barcode.url!.url default: // See API reference for all supported value types } }
Objective-C
for (MLKBarcode *barcode in barcodes) { NSArray *corners = barcode.cornerPoints; NSString *displayValue = barcode.displayValue; NSString *rawValue = barcode.rawValue; MLKBarcodeValueType valueType = barcode.valueType; switch (valueType) { case MLKBarcodeValueTypeWiFi: ssid = barcode.wifi.ssid; password = barcode.wifi.password; encryptionType = barcode.wifi.type; break; case MLKBarcodeValueTypeURL: url = barcode.URL.url; title = barcode.URL.title; break; // ... default: break; } }
טיפים לשיפור הביצועים בזמן אמת
כדי לסרוק ברקודים באפליקציה בזמן אמת, צריך לפעול לפי השלבים הבאים: כדי להשיג את קצבי הפריימים הטובים ביותר:
-
לא לצלם קלט ברזולוציה המקורית של המצלמה. במכשירים מסוימים, לכידת קלט ברזולוציה המקורית מפיקה גדול מאוד (10+ כך שזמן האחזור נמוך מאוד ואין תועלת מדויקות. במקום זאת, מבקשים מהמצלמה רק את הגודל הנדרש לסריקת ברקוד, שבדרך כלל לא עולה על 2 מגה-פיקסלים.
ההגדרות הקבועות מראש לסשן הצילום שקיבלו שם –
AVCaptureSessionPresetDefault
,AVCaptureSessionPresetLow
,AVCaptureSessionPresetMedium
וכן הלאה) – לא מומלץ, כי הם יכולים למפות ורזולוציות לא מתאימות במכשירים מסוימים. במקום זאת, משתמשים בהגדרות הקבועות מראש הספציפיות כמוAVCaptureSessionPreset1280x720
.אם מהירות הסריקה חשובה, אפשר להאט עוד יותר את צילום התמונה ורזולוציה. עם זאת, חשוב לזכור את הדרישות המינימליות לגודל הברקוד שתוארו למעלה.
אם מנסים לזהות ברקודים מתוך רצף של סטרימינג אחר פריימים, המזהה עשוי להפיק תוצאות שונות מהפריים מסגרת. צריך להמתין עד שמקבלים סדרה רציפה של אותה רמה כדי להיות בטוחים שהחזרתם תוצאה טובה.
אין תמיכה בספרת ביקורת (checksum) ב-ITF וב-CODE-39.
- כדי לעבד פריימים של וידאו, צריך להשתמש ב-API הסינכרוני
results(in:)
של הגלאי. שיחת טלפון שיטה זו מAVCaptureVideoDataOutputSampleBufferDelegate
פונקציהcaptureOutput(_, didOutput:from:)
לקבלת תוצאות בסרטון הנתון באופן סינכרוני מסגרת. שמור את שלAVCaptureVideoDataOutput
alwaysDiscardsLateVideoFrames
בתורtrue
כדי לווסת שיחות למזהה. אם תג חדש פריים הווידאו יהפוך לזמין כשהגלאי פועל, הוא יוסר. - אם משתמשים בפלט של הגלאי כדי להציג גרפיקה בשכבת-על מקבלים קודם את התוצאה מ-ML Kit ואז מעבדים את התמונה וליצור שכבת-על בשלב אחד. כך תוכלו להציג את משטח המסך רק פעם אחת לכל מסגרת קלט שעברה עיבוד. אפשר לעיין בתצוגה updatePreviewOverlayViewWithLastFrame בדוגמת המדריך למתחילים ל-ML Kit.