يمكنك استخدام مجموعة أدوات تعلُّم الآلة للتعرّف على الرموز الشريطية وفك ترميزها.
جرّبه الآن
- يمكنك تجربة نموذج التطبيق من أجل يمكنك الاطّلاع على مثال حول استخدام واجهة برمجة التطبيقات هذه.
قبل البدء
- تضمين مجموعات ML Kit التالية في Podfile:
pod 'GoogleMLKit/BarcodeScanning', '15.5.0'
- بعد تثبيت لوحات مشروعك أو تحديثها، افتح مشروع Xcode باستخدام
.xcworkspace
تتوفّر حزمة تعلّم الآلة في الإصدار 12.4 من Xcode أو الإصدارات الأحدث.
إرشادات إدخال الصور
-
لكي تتمكن أدوات تعلّم الآلة من قراءة الرموز الشريطية بدقة، يجب أن تحتوي الصور المدخلة على الرموز الشريطية التي يتم تمثيلها ببيانات بكسل كافية.
تعتمد المتطلبات المحددة لبيانات البكسل على كل من نوع الرمز الشريطي ومقدار البيانات المشفرة فيه، نظرًا لأن العديد من الرموز الشريطية تدعم حمولة بيانات ذات حجم متغير. وبشكل عام، تُعد أصغر معنى يجب ألا يقل عرض وحدة الرمز الشريطي عن 2 بكسل رموز ثنائية الأبعاد، بطول 2 بكسل
على سبيل المثال، تتكون الرموز الشريطية EAN-13 من الأشرطة والمسافات التي تبلغ 1، بعرض 2 أو 3 أو 4 وحدات، لذا من المفترض أن تحتوي صورة الرمز الشريطي EAN-13 على أشرطة المساحات التي لا يقل عرضها عن 2 و4 و6 و8 بكسل. لأنّ رقم EAN-13 يبلغ عرض الرمز الشريطي 95 وحدة، ويجب ألا يقل عرض الرمز الشريطي عن 190 وحدة عرض البكسل.
تحتاج التنسيقات الأكثر كثافة، مثل PDF417، إلى أبعاد بكسل أكبر تكنولوجيا تعلُّم الآلة لقراءتها بشكلٍ موثوق. على سبيل المثال، يمكن أن يتضمن رمز PDF417 ما يصل إلى "كلمة" بعرض 34 وحدة 17 في صف واحد، والذي من المفترض أن يكون على الأقل عرض 1156 بكسل
-
يمكن أن يؤثر التركيز الضعيف للصورة على دقة المسح الضوئي. إذا لم يحصل تطبيقك على نتائج مقبولة، اطلب من المستخدم تلخيص الصورة.
-
بالنسبة إلى التطبيقات النموذجية، يوصى بتوفير مستوى أعلى من درجة الدقة، مثل 1280x720 أو 1920x1080، مما يجعل الرموز الشريطية يمكن مسحه ضوئيًا من مسافة أكبر بعيدًا عن الكاميرا.
ولكن في التطبيقات التي يكون فيها وقت الاستجابة مهمًا، يمكنك تحسين الأداء من خلال التقاط الصور بدقة أقل، ولكن يتطلب ذلك يشكل الرمز الشريطي غالبية الصورة التي تم إدخالها. راجع أيضًا نصائح لتحسين الأداء في الوقت الفعلي.
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];
التنسيقات التالية متاحة:
- الرمز البرمجي-128 (
MLKBarcodeFormatCode128
) - الرمز-39 (
MLKBarcodeFormatCode39
) - الرمز-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:)
الخاصة بأداة الرصد. اتصل لهذه الطريقة منAVCaptureVideoDataOutputSampleBufferDelegate
captureOutput(_, didOutput:from:)
للحصول على النتائج من الفيديو المحدّد بشكل متزامن الإطار. إبقاء جهازAVCaptureVideoDataOutput
alwaysDiscardsLateVideoFrames
كـtrue
لضبط الاتصالات الموجَّهة إلى أداة الرصد. إذا كانت تجربة يصبح إطار الفيديو متاحًا أثناء تشغيل أداة الكشف، وسيتم إسقاطه. - إذا استخدمت مخرجات أداة الكشف لتراكب الرسومات على الصورة المدخلة، والحصول أولاً على النتيجة من ML Kit، ثم عرض الصورة وتراكبها في خطوة واحدة. ومن خلال القيام بذلك، يمكنك العرض على سطح الشاشة مرة واحدة فقط لكل إطار إدخال تمت معالجته. راجع updatePreviewOverlayViewWithLastFrame في عينة البدء السريع لأدوات تعلُّم الآلة كمثال.