يمكنك استخدام مجموعة أدوات تعلُّم الآلة للتعرّف على الرموز الشريطية وفك ترميزها.
قبل البدء
- إذا لم يسبق لك إضافة Firebase إلى تطبيقك، يمكنك إجراء ذلك من خلال اتّباع الخطوات الأولى في دليل البدء.
- تضمين مكتبات ML Kit في Podfile:
pod 'Firebase/MLVision' pod 'Firebase/MLVisionBarcodeModel'
بعد تثبيت مجموعات مشروعك الصغيرة أو تحديثها، احرص على فتح ملف Xcode باستخدام.xcworkspace
. - في تطبيقك، استورد Firebase:
Swift
import Firebase
Objective-C
@import Firebase;
إرشادات إدخال الصور
-
لكي تتمكن أدوات تعلّم الآلة من قراءة الرموز الشريطية بدقة، يجب أن تحتوي الصور المدخلة على الرموز الشريطية التي يتم تمثيلها ببيانات بكسل كافية.
تعتمد المتطلبات المحددة لبيانات البكسل على كل من نوع الرمز الشريطي ومقدار البيانات المشفرة فيه (بما أن معظم الرموز الشريطية) تدعم حمولة متغيرة الطول). وبشكل عام، تُعد أصغر معنى يجب ألا يقل عرض وحدة الرمز الشريطي عن 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 ورموز الاستجابة السريعة فقط، يمكنك إنشاء
VisionBarcodeDetectorOptions
كما في
المثال التالي:
Swift
let format = VisionBarcodeFormat.all let barcodeOptions = VisionBarcodeDetectorOptions(formats: format)
التنسيقات التالية متاحة:
- الرمز 128
- الرمز 39
- الرمز 93
- كودا بار
- رقم EAN13
- رقم EAN8
- ITF
- UPCA
- UPCE
- رمز الاستجابة السريعة
- PDF417
- أزتكي
- مصفوفة البيانات
Objective-C
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
: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 ميغابكسل)، وهو ما ينتج عنه وقت استجابة ضعيف جدًا بدون الاستفادة ودقتها. بدلاً من ذلك، اطلب فقط المقاس المطلوب من الكاميرا. لاكتشاف الرمز الشريطي: لا يزيد حجمها عادةً عن 2 ميغابكسل.
الإعدادات المسبقة لجلسة التسجيل المُسمّاة:
AVCaptureSessionPresetDefault
AVCaptureSessionPresetLow
،AVCaptureSessionPresetMedium
، وما إلى ذلك) - لا يوصى بها، حيث يمكنهم التعيين إلى ودرجات الدقة غير المناسبة على بعض الأجهزة. بدلاً من ذلك، استخدم الإعدادات المسبقة المحددة مثلAVCaptureSessionPreset1280x720
.إذا كانت سرعة المسح الضوئي مهمة، يمكنك تقليل التقاط الصورة أكثر الحل. مع ذلك، يجب الانتباه إلى الحدّ الأدنى لمتطلبات حجم الرمز الشريطي. الموضحة أعلاه.
- التحكُّم في المكالمات الواردة إلى أداة الرصد. إذا أصبح إطار فيديو جديد المتاح أثناء تشغيل أداة الكشف، أفلِت الإطار.
- إذا كنت تستخدم ناتج أداة الكشف لتراكب الرسومات على الصورة المدخلة، والحصول أولاً على النتيجة من ML Kit، ثم عرض الصورة وتراكبها في خطوة واحدة. ومن خلال القيام بذلك، يمكنك العرض على سطح الشاشة مرة واحدة فقط لكل إطار إدخال اطّلع على previewOverlayView وFIRDetectionOverlayView الفئات في نموذج تطبيق العرض كمثال.