אתם יכולים להשתמש ב-ML Kit כדי לזהות ולפענח קודי מ barras.
לפני שמתחילים
- אם עדיין לא הוספתם את Firebase לאפליקציה, צריך לבצע את הפעולות הבאות במדריך לתחילת העבודה.
- כוללים את ספריות ML Kit ב-Podfile:
אחרי שמתקינים או מעדכנים את קבוצות ה-Pod של הפרויקט, חשוב לפתוח את ה-Xcode באמצעות ה-pod 'Firebase/MLVision' pod 'Firebase/MLVisionBarcodeModel'
.xcworkspace
שלו. - מייבאים את Firebase לאפליקציה:
Swift
import Firebase
Objective-C
@import Firebase;
הנחיות להוספת תמונה
-
כדי ש-ML Kit יוכל לקרוא ברקודים באופן מדויק, תמונות הקלט חייבות להכיל ברקודים שמיוצגים על ידי כמות מספקת של נתוני פיקסלים.
הדרישות הספציפיות לנתוני הפיקסלים תלויות גם בסוג הברקוד וגם בכמות הנתונים שמקודדים בו (כי רוב הברקודים תומכים בתוכן טעון באורך משתנה). באופן כללי, המשמעות יחידת הברקוד צריכה להיות ברוחב 2 פיקסלים לפחות קודים דו-ממדיים, בגובה של 2 פיקסלים).
לדוגמה, ברקודים מסוג EAN-13 מורכבים מעמודות ומרווחים שהם 1, רוחב של 2, 3 או 4 יחידות, כך שתמונת ברקוד מסוג EAN-13 באופן אידיאלי כוללת פסים רווחים ברוחב 2, 4, 6 ו-8 פיקסלים לפחות. מאחר שתקן EAN-13 הברקוד הוא ברוחב 95 יחידות. הוא צריך להיות לפחות 190 יחידות פיקסלים לרוחב.
בפורמטים צפופים יותר, כמו PDF417, נדרשים מידות פיקסלים גבוהות יותר ML Kit כדי לקרוא אותם בצורה אמינה. לדוגמה, קוד PDF417 יכול לכלול עד 34 "מילים" ברוחב 17 יחידות בשורה אחת, שרוחב הרצוי שלה הוא לפחות 1,156 פיקסלים.
-
מיקוד תמונה לא טוב עלול לפגוע בדיוק הסריקה. אם התוצאות לא מתקבלות, נסו לבקש מהמשתמש לצלם מחדש את התמונה.
-
באפליקציות טיפוסיות מומלץ לספק ערך גבוה יותר תמונה ברזולוציה גבוהה (למשל 1280x720 או 1920x1080), שמפיקה ברקודים. במרחק גדול יותר מהמצלמה.
עם זאת, באפליקציות שבהן זמן האחזור קריטי, ניתן לשפר צילום תמונות ברזולוציה נמוכה יותר, אבל נדרש הברקוד מהווה את רוב תמונת הקלט. מומלץ לקרוא גם את המאמר טיפים לשיפור הביצועים בזמן אמת.
1. הגדרת גלאי הברקוד
אם ידוע לך אילו פורמטים של ברקוד היית רוצה לקרוא, אפשר להאיץ את התהליך של מזהה הברקוד על ידי הגדרתו כך שיזהה רק את הפורמטים האלה.לדוגמה, כדי לזהות רק קוד אצטקי וקודי QR,
באובייקט VisionBarcodeDetectorOptions
, כמו
בדוגמה הבאה:
Swift
let format = VisionBarcodeFormat.all let barcodeOptions = VisionBarcodeDetectorOptions(formats: format)
הפורמטים הבאים נתמכים:
- Code128
- קוד39
- Code93
- CodaBar
- מספר EAN13
- EAN8
- ITF
- UPCA
- UPCE
- קוד QR
- PDF417
- אצטקים
- DataMatrix
Objective-C
FIRVisionBarcodeDetectorOptions *options = [[FIRVisionBarcodeDetectorOptions alloc] initWithFormats: FIRVisionBarcodeFormatQRCode | FIRVisionBarcodeFormatAztec];
הפורמטים הבאים נתמכים:
- קוד 128 (
FIRVisionBarcodeFormatCode128
) - קוד 39 (
FIRVisionBarcodeFormatCode39
) - קוד 93 (
FIRVisionBarcodeFormatCode93
) - Codabar (
FIRVisionBarcodeFormatCodaBar
) - EAN-13 (
FIRVisionBarcodeFormatEAN13
) - EAN-8 (
FIRVisionBarcodeFormatEAN8
) - ITF (
FIRVisionBarcodeFormatITF
) - UPC-A (
FIRVisionBarcodeFormatUPCA
) - UPC-E (
FIRVisionBarcodeFormatUPCE
) - קוד QR (
FIRVisionBarcodeFormatQRCode
) - PDF417 (
FIRVisionBarcodeFormatPDF417
) - אצטקית (
FIRVisionBarcodeFormatAztec
) - מטריצת נתונים (
FIRVisionBarcodeFormatDataMatrix
)
2. הפעלת גלאי הברקוד
כדי לסרוק ברקודים בתמונה, מעבירים את התמונה כ-UIImage
או
CMSampleBufferRef
ל-detect(in:)
של VisionBarcodeDetector
method:
- מקבלים מופע של
VisionBarcodeDetector
:Swift
lazy var vision = Vision.vision() let barcodeDetector = vision.barcodeDetector(options: barcodeOptions)
Objective-C
FIRVision *vision = [FIRVision vision]; FIRVisionBarcodeDetector *barcodeDetector = [vision barcodeDetector]; // Or, to change the default settings: // FIRVisionBarcodeDetector *barcodeDetector = // [vision barcodeDetectorWithOptions:options];
-
יצירת אובייקט
VisionImage
באמצעותUIImage
אוCMSampleBufferRef
כדי להשתמש ב-
UIImage
:- במקרה הצורך, מסובבים את התמונה כך ש-
imageOrientation
הוא.up
. - יצירת אובייקט
VisionImage
באמצעות סיבוב נכוןUIImage
. אל תציינו מטא-נתונים של סבב, ברירת המחדל יש להשתמש בערך.topLeft
.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
כדי להשתמש ב-
CMSampleBufferRef
:-
יוצרים אובייקט
VisionImageMetadata
שמציין את של נתוני התמונה שכלולים מאגר נתונים זמני שלCMSampleBufferRef
.כדי לקבל את כיוון התמונה:
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> VisionDetectorImageOrientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftTop : .rightTop case .landscapeLeft: return cameraPosition == .front ? .bottomLeft : .topLeft case .portraitUpsideDown: return cameraPosition == .front ? .rightBottom : .leftBottom case .landscapeRight: return cameraPosition == .front ? .topRight : .bottomRight case .faceDown, .faceUp, .unknown: return .leftTop } }
Objective-C
- (FIRVisionDetectorImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationLeftTop; } else { return FIRVisionDetectorImageOrientationRightTop; } case UIDeviceOrientationLandscapeLeft: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationBottomLeft; } else { return FIRVisionDetectorImageOrientationTopLeft; } case UIDeviceOrientationPortraitUpsideDown: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationRightBottom; } else { return FIRVisionDetectorImageOrientationLeftBottom; } case UIDeviceOrientationLandscapeRight: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationTopRight; } else { return FIRVisionDetectorImageOrientationBottomRight; } default: return FIRVisionDetectorImageOrientationTopLeft; } }
לאחר מכן, יוצרים את אובייקט המטא-נתונים:
Swift
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Objective-C
FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; AVCaptureDevicePosition cameraPosition = AVCaptureDevicePositionBack; // Set to the capture device you used. metadata.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
- יוצרים אובייקט
VisionImage
באמצעות אובייקטCMSampleBufferRef
והמטא-נתונים של הסבב:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- במקרה הצורך, מסובבים את התמונה כך ש-
-
לאחר מכן, מעבירים את התמונה לשיטה
detect(in:)
:Swift
barcodeDetector.detect(in: visionImage) { features, error in guard error == nil, let features = features, !features.isEmpty else { // ... return } // ... }
Objective-C
[barcodeDetector detectInImage:image completion:^(NSArray<FIRVisionBarcode *> *barcodes, NSError *error) { if (error != nil) { return; } else if (barcodes != nil) { // Recognized barcodes // ... } }];
3. קבלת מידע מברקודים
אם פעולת זיהוי הברקוד מצליחה, הגלאי מחזיר מערך שלVisionBarcode
אובייקטים. כל אובייקט VisionBarcode
מייצג
הברקוד שזוהה בתמונה. לכל ברקוד אפשר לראות
וגם את הקואורדינטות התוחמות בתמונת הקלט, וגם את הנתונים הגולמיים המקודדים על ידי
ברקוד. אם גלאי הברקוד הצליח לזהות את סוג הנתונים,
שמקודדים לפי הברקוד, אפשר לקבל אובייקט שמכיל נתונים שנותחו.
לדוגמה:
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 (FIRVisionBarcode *barcode in barcodes) { NSArray *corners = barcode.cornerPoints; NSString *displayValue = barcode.displayValue; NSString *rawValue = barcode.rawValue; FIRVisionBarcodeValueType valueType = barcode.valueType; switch (valueType) { case FIRVisionBarcodeValueTypeWiFi: // ssid = barcode.wifi.ssid; // password = barcode.wifi.password; // encryptionType = barcode.wifi.type; break; case FIRVisionBarcodeValueTypeURL: // url = barcode.URL.url; // title = barcode.URL.title; break; // ... default: break; } }
טיפים לשיפור הביצועים בזמן אמת
כדי לסרוק ברקודים באפליקציה בזמן אמת, צריך לפעול לפי השלבים הבאים: כדי להשיג את קצבי הפריימים הטובים ביותר:
-
לא לצלם קלט ברזולוציה המקורית של המצלמה. במכשירים מסוימים, צילום הקלט ברזולוציה המקורית יוצר תמונות גדולות מאוד (יותר מ-10 מגה-פיקסלים), וכתוצאה מכך זמן האחזור (latency) נמוך מאוד ללא שיפור ברמת הדיוק. במקום זאת, צריך לבקש מהמצלמה רק את הגודל שנחוץ לזיהוי ברקוד: בדרך כלל לא יותר מ-2 מגה-פיקסלים.
ההגדרות הקבועות מראש לסשן הצילום שקיבלו שם –
AVCaptureSessionPresetDefault
,AVCaptureSessionPresetLow
,AVCaptureSessionPresetMedium
וכן הלאה) – לא מומלץ, כי הם יכולים למפות ורזולוציות לא מתאימות במכשירים מסוימים. במקום זאת, משתמשים בהגדרות הקבועות מראש הספציפיות כמוAVCaptureSessionPreset1280x720
.אם מהירות הסריקה חשובה, אפשר להאט עוד יותר את צילום התמונה ורזולוציה. עם זאת, חשוב לזכור את הדרישות המינימליות לגודל הברקוד שתוארו למעלה.
- צמצום מספר הקריאות למזהה. אם פריים חדש בסרטון הופך בזמן שהגלאי פועל, משחררים את הפריים.
- אם משתמשים בפלט של הגלאי כדי להציג גרפיקה בשכבת-על מקבלים קודם את התוצאה מ-ML Kit ואז מעבדים את התמונה וליצור שכבת-על בשלב אחד. כך תוכלו להציג את משטח המסך פעם אחת בלבד לכל מסגרת קלט. אפשר לעיין ב-previewOverlayView ו-FIRDetectionOverlayView באפליקציה לדוגמה של Showcase.