يمكنك استخدام أدوات تعلّم الآلة للتعرّف على الرموز الشريطية وفك ترميزها.
تجربة السمات والبيانات
- جرِّب نموذج التطبيق للاطّلاع على مثال حول استخدام واجهة برمجة التطبيقات هذه.
قبل البدء
- أدرِج مجموعات تعلّم الآلة التالية في Podfile:
pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
- بعد تثبيت أو تحديث مجموعات Pods لمشروعك، افتح مشروع Xcode باستخدام
.xcworkspace
. تتوفّر هذه الأداة في الإصدار 12.4 من Xcode أو إصدار أحدث.
إرشادات إدخال الصورة
-
لكي تتمكّن أدوات تعلُّم الآلة من قراءة الرموز الشريطية بدقة، يجب أن تتضمّن الصور المدخلة رموزًا شريطية تمثّل بيانات بكسل كافية.
وتعتمد متطلبات بيانات البكسل المحددة على نوع الرمز الشريطي وكمية البيانات التي يتم ترميزها فيه، لأنّ العديد من الرموز الشريطية تتيح استخدام حمولة ذات حجم متغير. وبشكل عام، يجب ألا يقل عرض الوحدة الأصغر حجمًا للرمز الشريطي عن 2 بكسل، وألا يقل طول الرموز الثنائية الأبعاد عن 2 بكسل.
على سبيل المثال، تتألف الرموز الشريطية لرقم EAN-13 من أشرطة ومسافات بعرض 1 أو 2 أو 3 أو 4 وحدات، لذا من الأفضل أن تحتوي الصورة الشريطية لرقم EAN-13 على أشرطة ومسافات لا يقلّ عرضها عن 2 و4 و6 و8 بكسل. يجب أن يبلغ عرض الرمز الشريطي EAN-13 95 وحدة بكسل على الأقلّ.
إنّ التنسيقات الأكثر كثافة، مثل PDF417، تحتاج إلى أبعاد أكبر لوحدات البكسل كي تقرأها بشكل موثوق. على سبيل المثال، يمكن أن يتضمّن الرمز PDF417 ما يصل إلى 34 "كلمة" بعرض 17 وحدة في صف واحد، ويُفضَّل ألّا يقل عرضها عن 1156 بكسل.
-
يمكن أن يؤثّر التركيز السيئ للصورة في دقة المسح الضوئي. إذا لم يحصل تطبيقك على نتائج مقبولة، اطلب من المستخدم إعادة التقاط الصورة.
-
في التطبيقات العادية، يُنصح بتوفير صورة ذات دقة أعلى، مثل 1280×720 أو 1920×1080، ما يجعل الرموز الشريطية قابلة للمسح الضوئي على مسافة أكبر بعيدًا عن الكاميرا.
ومع ذلك، في التطبيقات التي يكون فيها وقت الاستجابة أمرًا بالغ الأهمية، يمكنك تحسين الأداء من خلال التقاط الصور بدقة أقل، ولكن يجب أن يكون الرمز الشريطي لمعظم الصور التي يتم إدخالها. راجِع أيضًا نصائح لتحسين الأداء في الوقت الفعلي.
1- ضبط الماسح الضوئي للرموز الشريطية
إذا كنت تعرف تنسيقات الرمز الشريطي التي تتوقع قراءتها، يمكنك تحسين سرعة الماسح الضوئي للرموز الشريطية من خلال تكوينه لمسح تلك التنسيقات فقط.على سبيل المثال، لمسح رمز Aztec ورموز الاستجابة السريعة فقط ضوئيًا، يمكنك إنشاء كائن 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];
تتوفّر التنسيقات التالية:
- Code-128 (
MLKBarcodeFormatCode128
) - الرمز-39 (
MLKBarcodeFormatCode39
) - Code-93 (
MLKBarcodeFormatCode93
) - كودابار (
MLKBarcodeFormatCodaBar
) - مصفوفة البيانات (
MLKBarcodeFormatDataMatrix
) - رقم EAN-13 (
MLKBarcodeFormatEAN13
) - رقم EAN-8 (
MLKBarcodeFormatEAN8
) - ITF (
MLKBarcodeFormatITF
) - رمز الاستجابة السريعة (
MLKBarcodeFormatQRCode
) - الرمز العالمي للمنتج (UPC-A) (
MLKBarcodeFormatUPCA
) - الرمز العالمي للمنتج (UPC-E) (
MLKBarcodeFormatUPCE
) - PDF-417 (
MLKBarcodeFormatPDF417
) - رمز Aztec (
MLKBarcodeFormatAztec
)
2. تحضير صورة الإدخال
لمسح الرموز الشريطية ضوئيًا في صورة، مرِّر الصورة كـUIImage
أو CMSampleBufferRef
إلى طريقة process()
أو results(in:)
في BarcodeScanner
:
أنشِئ عنصر 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. معالجة الصورة
بعد ذلك، أدخِل الصورة إلى طريقةprocess()
:
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
.وإذا كانت سرعة المسح الضوئي مهمة، يمكنك خفض درجة دقة التقاط الصورة أكثر. ومع ذلك، يجب مراعاة الحدّ الأدنى لمتطلبات حجم الرمز الشريطي الموضّحة أعلاه.
إذا كنت تحاول التعرّف على الرموز الشريطية من سلسلة من إطارات الفيديو المباشر، قد تقدّم أداة التعرّف على نتائج مختلفة من إطار إلى آخر. وعليك الانتظار إلى أن تحصل على سلسلة متتالية من القيمة نفسها لضمان عرض نتيجة جيدة.
لا يمكن استخدام رقم المجموع الاختباري مع ITF وCODE-39.
- لمعالجة إطارات الفيديو، استخدِم واجهة برمجة التطبيقات المتزامنة
results(in:)
لأداة الرصد. ويمكنك استدعاء هذه الطريقة من وظيفةcaptureOutput(_, didOutput:from:)
فيAVCaptureVideoDataOutputSampleBufferDelegate
للحصول على نتائج متزامنة من إطار الفيديو المحدّد. الاحتفاظ بـAVCaptureVideoDataOutput
alwaysDiscardsLateVideoFrames
true
لتقليل المكالمات الواردة إلى جهاز الرصد. في حال توفّر إطار فيديو جديد أثناء تشغيل أداة الرصد، سيتم تجاهله. - إذا كنت تستخدم نتيجة أداة الرصد لإضافة رسومات على الصورة التي تم إدخالها، احصل أولاً على النتيجة من أدوات تعلّم الآلة، ثم اعرض الصورة والتراكب في خطوة واحدة. بإجراء ذلك، يتم عرضك على سطح الشاشة مرة واحدة فقط لكل إطار إدخال تمت معالجته. للاطّلاع على مثال، يمكن الاطّلاع على updatePreviewOverlayViewWithLastFrame في نموذج البدء السريع في ML Kit.