يمكنك استخدام ML Kit للتعرف على الرموز الشريطية وفك تشفيرها.
قبل ان تبدأ
- إذا لم تكن قد أضفت Firebase إلى تطبيقك بالفعل، فقم بذلك باتباع الخطوات الواردة في دليل البدء .
- قم بتضمين مكتبات ML Kit في ملف Podfile الخاص بك:
pod 'Firebase/MLVision' pod 'Firebase/MLVisionBarcodeModel'
بعد تثبيت أو تحديث Pods لمشروعك، تأكد من فتح مشروع Xcode الخاص بك باستخدام.xcworkspace
. - في تطبيقك، قم باستيراد Firebase:
سويفت
import Firebase
ج موضوعية
@import Firebase;
إرشادات إدخال الصورة
لكي تتمكن ML Kit من قراءة الرموز الشريطية بدقة، يجب أن تحتوي الصور المدخلة على رموز شريطية يتم تمثيلها ببيانات بكسل كافية.
تعتمد متطلبات بيانات البكسل المحددة على كل من نوع الرمز الشريطي وكمية البيانات المشفرة فيه (نظرًا لأن معظم الرموز الشريطية تدعم حمولة متغيرة الطول). بشكل عام، يجب أن تكون أصغر وحدة ذات معنى في الباركود بعرض 2 بكسل على الأقل (وبالنسبة للرموز ثنائية الأبعاد، يبلغ طولها 2 بكسل).
على سبيل المثال، تتكون الرموز الشريطية EAN-13 من أشرطة ومسافات يبلغ عرضها 1 أو 2 أو 3 أو 4 وحدات، لذلك تحتوي صورة الرمز الشريطي EAN-13 بشكل مثالي على أشرطة ومسافات يبلغ عرضها 2 و4 و6 و6 على الأقل. 8 بكسل واسعة. نظرًا لأن عرض الرمز الشريطي EAN-13 يبلغ إجماليًا 95 وحدة، فيجب أن يكون عرض الرمز الشريطي 190 بكسل على الأقل.
تحتاج التنسيقات الأكثر كثافة، مثل PDF417، إلى أبعاد بكسل أكبر حتى تتمكن ML Kit من قراءتها بشكل موثوق. على سبيل المثال، يمكن أن يحتوي كود PDF417 على ما يصل إلى 34 "كلمة" بعرض 17 وحدة في صف واحد، والتي من المفترض أن يبلغ عرضها 1156 بكسل على الأقل.
قد يؤدي التركيز الضعيف للصورة إلى الإضرار بدقة المسح الضوئي. إذا لم تحصل على نتائج مقبولة، فحاول مطالبة المستخدم باستعادة الصورة.
بالنسبة للتطبيقات النموذجية، يوصى بتوفير صورة بدقة أعلى (مثل 1280 × 720 أو 1920 × 1080)، مما يجعل الرموز الشريطية قابلة للاكتشاف من مسافة أكبر بعيدًا عن الكاميرا.
ومع ذلك، في التطبيقات التي يكون فيها زمن الاستجابة أمرًا بالغ الأهمية، يمكنك تحسين الأداء عن طريق التقاط الصور بدقة أقل، ولكن يتطلب أن يشكل الرمز الشريطي غالبية الصورة المدخلة. راجع أيضًا نصائح لتحسين الأداء في الوقت الفعلي .
1. قم بتكوين كاشف الباركود
إذا كنت تعرف تنسيقات الباركود التي تتوقع قراءتها، فيمكنك تحسين سرعة كاشف الباركود عن طريق تكوينه لاكتشاف تلك التنسيقات فقط. على سبيل المثال، لاكتشاف رمز Aztec ورموز QR فقط، قم بإنشاء كائن VisionBarcodeDetectorOptions
كما في المثال التالي:
سويفت
let format = VisionBarcodeFormat.all let barcodeOptions = VisionBarcodeDetectorOptions(formats: format)
يتم دعم التنسيقات التالية:
- كود128
- كود39
- كود93
- كودابار
- EAN13
- EAN8
- الـITF
- UPCA
- UPCE
- رمز الاستجابة السريعة
- PDF417
- الأزتيك
- مصفوفة البيانات
ج موضوعية
FIRVisionBarcodeDetectorOptions *options = [[FIRVisionBarcodeDetectorOptions alloc] initWithFormats: FIRVisionBarcodeFormatQRCode | FIRVisionBarcodeFormatAztec];
يتم دعم التنسيقات التالية:
- كود 128 (
FIRVisionBarcodeFormatCode128
) - الكود 39 (
FIRVisionBarcodeFormatCode39
) - كود 93 (
FIRVisionBarcodeFormatCode93
) - كودابار (
FIRVisionBarcodeFormatCodaBar
) - EAN-13 (
FIRVisionBarcodeFormatEAN13
) - EAN-8 (
FIRVisionBarcodeFormatEAN8
) - الـITF (
FIRVisionBarcodeFormatITF
) - UPC-A (
FIRVisionBarcodeFormatUPCA
) - UPC-E (
FIRVisionBarcodeFormatUPCE
) - رمز الاستجابة السريعة (
FIRVisionBarcodeFormatQRCode
) - PDF417 (
FIRVisionBarcodeFormatPDF417
) - ازتيك (
FIRVisionBarcodeFormatAztec
) - مصفوفة البيانات (
FIRVisionBarcodeFormatDataMatrix
)
2. قم بتشغيل كاشف الباركود
لمسح الرموز الشريطية في صورة ما، قم بتمرير الصورة كـUIImage
أو CMSampleBufferRef
إلى طريقة detect(in:)
VisionBarcodeDetector
:- الحصول على مثيل
VisionBarcodeDetector
:سويفت
lazy var vision = Vision.vision() let barcodeDetector = vision.barcodeDetector(options: barcodeOptions)
ج موضوعية
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
.سويفت
let image = VisionImage(image: uiImage)
ج موضوعية
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
لاستخدام
CMSampleBufferRef
:قم بإنشاء كائن
VisionImageMetadata
الذي يحدد اتجاه بيانات الصورة الموجودة في المخزن المؤقتCMSampleBufferRef
.للحصول على اتجاه الصورة:
سويفت
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 } }
ج موضوعية
- (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; } }
ثم قم بإنشاء كائن بيانات التعريف:
سويفت
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
ج موضوعية
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
وبيانات تعريف التدوير:سويفت
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
ج موضوعية
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- إذا لزم الأمر، قم بتدوير الصورة بحيث تكون خاصية
- ثم قم بتمرير الصورة إلى طريقة
detect(in:)
:سويفت
barcodeDetector.detect(in: visionImage) { features, error in guard error == nil, let features = features, !features.isEmpty else { // ... return } // ... }
ج موضوعية
[barcodeDetector detectInImage:image completion:^(NSArray<FIRVisionBarcode *> *barcodes, NSError *error) { if (error != nil) { return; } else if (barcodes != nil) { // Recognized barcodes // ... } }];
3. الحصول على المعلومات من الباركود
إذا نجحت عملية التعرف على الرمز الشريطي، فسيقوم الكاشف بإرجاع مجموعة من كائناتVisionBarcode
. يمثل كل كائن VisionBarcode
رمزًا شريطيًا تم اكتشافه في الصورة. بالنسبة لكل رمز شريطي، يمكنك الحصول على إحداثياته المحيطة في الصورة المدخلة، بالإضافة إلى البيانات الأولية المشفرة بواسطة الرمز الشريطي. وأيضًا، إذا كان كاشف الباركود قادرًا على تحديد نوع البيانات المشفرة بواسطة الباركود، فيمكنك الحصول على كائن يحتوي على بيانات تم تحليلها.على سبيل المثال:
سويفت
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 } }
ج موضوعية
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 ميجابكسل)، مما يؤدي إلى زمن استجابة ضعيف جدًا دون أي فائدة للدقة. بدلاً من ذلك، اطلب فقط الحجم المطلوب من الكاميرا لاكتشاف الرمز الشريطي: عادةً لا يزيد عن 2 ميجابكسل.
ومع ذلك، لا يُنصح باستخدام الإعدادات المسبقة لجلسة الالتقاط المسماة -
AVCaptureSessionPresetDefault
وAVCaptureSessionPresetLow
وAVCaptureSessionPresetMedium
وما إلى ذلك) - حيث يمكنها التعيين إلى دقة غير مناسبة على بعض الأجهزة. بدلاً من ذلك، استخدم الإعدادات المسبقة المحددة مثلAVCaptureSessionPreset1280x720
.إذا كانت سرعة المسح الضوئي مهمة، فيمكنك خفض دقة التقاط الصورة بشكل أكبر. ومع ذلك، ضع في اعتبارك الحد الأدنى لمتطلبات حجم الباركود الموضحة أعلاه.
- خنق المكالمات إلى الكاشف. إذا أصبح إطار فيديو جديد متاحًا أثناء تشغيل الكاشف، قم بإسقاط الإطار.
- إذا كنت تستخدم مخرجات الكاشف لتراكب الرسومات على الصورة المدخلة، فاحصل أولاً على النتيجة من ML Kit، ثم قم بعرض الصورة والتراكب في خطوة واحدة. من خلال القيام بذلك، يمكنك العرض على سطح العرض مرة واحدة فقط لكل إطار إدخال. راجع فئتي PreviewOverlayView و FIRDetectionOverlayView في نموذج تطبيق العرض للحصول على مثال.