يمكنك استخدام ML Kit للتعرف على النص في الصور. تحتوي ML Kit على واجهة برمجة التطبيقات (API) ذات الأغراض العامة المناسبة للتعرف على النص في الصور، مثل نص علامة الشارع، وواجهة برمجة التطبيقات (API) المحسنة للتعرف على نص المستندات. تشتمل واجهة برمجة التطبيقات للأغراض العامة على نماذج موجودة على الجهاز ونماذج مستندة إلى السحابة. يتوفر التعرف على نص المستند فقط كنموذج قائم على السحابة. راجع النظرة العامة لمقارنة النماذج السحابية والنماذج الموجودة على الجهاز.
قبل ان تبدأ
- إذا لم تكن قد أضفت Firebase إلى تطبيقك بالفعل، فقم بذلك باتباع الخطوات الواردة في دليل البدء .
- قم بتضمين مكتبات ML Kit في ملف Podfile الخاص بك:
pod 'Firebase/MLVision', '6.25.0' # If using an on-device API: pod 'Firebase/MLVisionTextModel', '6.25.0'
بعد تثبيت أو تحديث Pods لمشروعك، تأكد من فتح مشروع Xcode الخاص بك باستخدام.xcworkspace
. - في تطبيقك، قم باستيراد Firebase:
سويفت
import Firebase
ج موضوعية
@import Firebase;
إذا كنت تريد استخدام النموذج المستند إلى السحابة، ولم تقم بالفعل بتمكين واجهات برمجة التطبيقات المستندة إلى السحابة لمشروعك، فقم بذلك الآن:
- افتح صفحة ML Kit APIs لوحدة تحكم Firebase.
إذا لم تكن قد قمت بالفعل بترقية مشروعك إلى خطة تسعير Blaze، فانقر فوق ترقية للقيام بذلك. (سيُطلب منك الترقية فقط إذا لم يكن مشروعك مدرجًا في خطة Blaze.)
يمكن فقط للمشاريع على مستوى Blaze استخدام واجهات برمجة التطبيقات المستندة إلى السحابة.
- إذا لم تكن واجهات برمجة التطبيقات المستندة إلى السحابة ممكّنة بالفعل، فانقر على تمكين واجهات برمجة التطبيقات المستندة إلى السحابة .
إذا كنت تريد استخدام الطراز الموجود على الجهاز فقط، فيمكنك تخطي هذه الخطوة.
أنت الآن جاهز لبدء التعرف على النص في الصور.
إرشادات إدخال الصورة
لكي تتعرف ML Kit على النص بدقة، يجب أن تحتوي الصور المدخلة على نص يتم تمثيله ببيانات بيكسل كافية. من الناحية المثالية، بالنسبة للنص اللاتيني، يجب أن يكون حجم كل حرف 16 × 16 بكسل على الأقل. بالنسبة للنصوص الصينية واليابانية والكورية (المدعومة فقط بواسطة واجهات برمجة التطبيقات المستندة إلى السحابة)، يجب أن يكون كل حرف 24 × 24 بكسل. بالنسبة لجميع اللغات، لا توجد عمومًا أي فائدة تتعلق بالدقة في أن يكون حجم الأحرف أكبر من 24 × 24 بكسل.
لذا، على سبيل المثال، قد تعمل صورة بحجم 640 × 480 بشكل جيد لمسح بطاقة العمل التي تشغل العرض الكامل للصورة. لإجراء مسح ضوئي لمستند مطبوع على ورق بحجم letter، قد تكون هناك حاجة إلى صورة بحجم 720 × 1280 بكسل.
يمكن أن يؤثر التركيز الضعيف على الصورة على دقة التعرف على النص. إذا لم تحصل على نتائج مقبولة، فحاول مطالبة المستخدم باستعادة الصورة.
إذا كنت تتعرف على نص في تطبيق في الوقت الفعلي، فقد تحتاج أيضًا إلى مراعاة الأبعاد الإجمالية للصور المدخلة. يمكن معالجة الصور الأصغر حجمًا بشكل أسرع، وذلك لتقليل زمن الوصول، والتقاط الصور بدقة أقل (مع الأخذ في الاعتبار متطلبات الدقة المذكورة أعلاه) والتأكد من أن النص يشغل أكبر قدر ممكن من الصورة. راجع أيضًا نصائح لتحسين الأداء في الوقت الفعلي .
التعرف على النص في الصور
للتعرف على النص في صورة ما باستخدام نموذج موجود على الجهاز أو مستند إلى السحابة، قم بتشغيل أداة التعرف على النص كما هو موضح أدناه.
1. قم بتشغيل أداة التعرف على النص
قم بتمرير الصورة كـ "UIImage" أو "CMSampleBufferRef" إلى طريقة "process(_:completion:)" الخاصة بـ "VisionTextRecognizer":- احصل على مثيل
VisionTextRecognizer
عن طريق الاتصال إما بـonDeviceTextRecognizer
أوcloudTextRecognizer
:سويفت
لاستخدام النموذج الموجود على الجهاز:
let vision = Vision.vision() let textRecognizer = vision.onDeviceTextRecognizer()
لاستخدام النموذج السحابي:
let vision = Vision.vision() let textRecognizer = vision.cloudTextRecognizer() // Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages let options = VisionCloudTextRecognizerOptions() options.languageHints = ["en", "hi"] let textRecognizer = vision.cloudTextRecognizer(options: options)
ج موضوعية
لاستخدام النموذج الموجود على الجهاز:
FIRVision *vision = [FIRVision vision]; FIRVisionTextRecognizer *textRecognizer = [vision onDeviceTextRecognizer];
لاستخدام النموذج السحابي:
FIRVision *vision = [FIRVision vision]; FIRVisionTextRecognizer *textRecognizer = [vision cloudTextRecognizer]; // Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages FIRVisionCloudTextRecognizerOptions *options = [[FIRVisionCloudTextRecognizerOptions alloc] init]; options.languageHints = @[@"en", @"hi"]; FIRVisionTextRecognizer *textRecognizer = [vision cloudTextRecognizerWithOptions: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;
- إذا لزم الأمر، قم بتدوير الصورة بحيث تكون خاصية
- ثم قم بتمرير الصورة إلى طريقة
process(_:completion:)
:سويفت
textRecognizer.process(visionImage) { result, error in guard error == nil, let result = result else { // ... return } // Recognized text }
ج موضوعية
[textRecognizer processImage:image completion:^(FIRVisionText *_Nullable result, NSError *_Nullable error) { if (error != nil || result == nil) { // ... return; } // Recognized text }];
2. استخرج النص من كتل النص التي تم التعرف عليها
إذا نجحت عملية التعرف على النص، فسوف تقوم بإرجاع كائن [`VisionText`] [VisionText]. يحتوي كائن `VisionText` على النص الكامل الذي تم التعرف عليه في الصورة وصفر أو أكثر من كائنات [`VisionTextBlock`][VisionTextBlock]. يمثل كل `VisionTextBlock` كتلة نصية مستطيلة تحتوي على صفر أو أكثر من كائنات [`VisionTextLine`] [VisionTextLine]. يحتوي كل كائن `VisionTextLine` على صفر أو أكثر من كائنات [`VisionTextElement`] [VisionTextElement]، والتي تمثل الكلمات والكيانات الشبيهة بالكلمات (التواريخ والأرقام وما إلى ذلك). بالنسبة لكل كائن `VisionTextBlock` و`VisionTextLine` و`VisionTextElement`، يمكنك التعرف على النص في المنطقة والإحداثيات المحيطة بالمنطقة. على سبيل المثال:سويفت
let resultText = result.text for block in result.blocks { let blockText = block.text let blockConfidence = block.confidence let blockLanguages = block.recognizedLanguages let blockCornerPoints = block.cornerPoints let blockFrame = block.frame for line in block.lines { let lineText = line.text let lineConfidence = line.confidence let lineLanguages = line.recognizedLanguages let lineCornerPoints = line.cornerPoints let lineFrame = line.frame for element in line.elements { let elementText = element.text let elementConfidence = element.confidence let elementLanguages = element.recognizedLanguages let elementCornerPoints = element.cornerPoints let elementFrame = element.frame } } }
ج موضوعية
NSString *resultText = result.text; for (FIRVisionTextBlock *block in result.blocks) { NSString *blockText = block.text; NSNumber *blockConfidence = block.confidence; NSArray<FIRVisionTextRecognizedLanguage *> *blockLanguages = block.recognizedLanguages; NSArray<NSValue *> *blockCornerPoints = block.cornerPoints; CGRect blockFrame = block.frame; for (FIRVisionTextLine *line in block.lines) { NSString *lineText = line.text; NSNumber *lineConfidence = line.confidence; NSArray<FIRVisionTextRecognizedLanguage *> *lineLanguages = line.recognizedLanguages; NSArray<NSValue *> *lineCornerPoints = line.cornerPoints; CGRect lineFrame = line.frame; for (FIRVisionTextElement *element in line.elements) { NSString *elementText = element.text; NSNumber *elementConfidence = element.confidence; NSArray<FIRVisionTextRecognizedLanguage *> *elementLanguages = element.recognizedLanguages; NSArray<NSValue *> *elementCornerPoints = element.cornerPoints; CGRect elementFrame = element.frame; } } }
نصائح لتحسين الأداء في الوقت الحقيقي
إذا كنت تريد استخدام النموذج الموجود على الجهاز للتعرف على النص في تطبيق في الوقت الفعلي، فاتبع هذه الإرشادات لتحقيق أفضل معدلات الإطارات:
- خنق المكالمات إلى أداة التعرف على النص. إذا أصبح إطار فيديو جديد متاحًا أثناء تشغيل أداة التعرف على النص، فقم بإسقاط الإطار.
- إذا كنت تستخدم مخرجات أداة التعرف على النص لتراكب الرسومات على الصورة المدخلة، فاحصل أولاً على النتيجة من ML Kit، ثم اعرض الصورة والتراكب في خطوة واحدة. من خلال القيام بذلك، يمكنك العرض على سطح العرض مرة واحدة فقط لكل إطار إدخال. راجع فئتي PreviewOverlayView و FIRDetectionOverlayView في نموذج تطبيق العرض للحصول على مثال.
- فكر في التقاط الصور بدقة أقل. ومع ذلك، ضع في اعتبارك أيضًا متطلبات أبعاد الصورة لواجهة برمجة التطبيقات هذه.
الخطوات التالية
- قبل أن تقوم بنشر تطبيق يستخدم Cloud API في الإنتاج، يجب عليك اتخاذ بعض الخطوات الإضافية لمنع وتخفيف تأثير الوصول غير المصرح به إلى API .
التعرف على النص في صور المستندات
للتعرف على نص مستند، قم بتكوين وتشغيل أداة التعرف على نص المستند المستندة إلى السحابة كما هو موضح أدناه.
توفر واجهة API للتعرف على نص المستند، الموضحة أدناه، واجهة مصممة لتكون أكثر ملاءمة للعمل مع صور المستندات. ومع ذلك، إذا كنت تفضل الواجهة التي توفرها واجهة برمجة تطبيقات النص المتفرق، فيمكنك استخدامها بدلاً من ذلك لمسح المستندات ضوئيًا عن طريق تكوين أداة التعرف على النص السحابي لاستخدام نموذج النص الكثيف .
لاستخدام واجهة برمجة تطبيقات التعرف على نص المستند:
1. قم بتشغيل أداة التعرف على النص
قم بتمرير الصورة كـUIImage
أو CMSampleBufferRef
إلى طريقة عملية VisionDocumentTextRecognizer
process(_:completion:)
:- احصل على مثيل
VisionDocumentTextRecognizer
عن طريق استدعاءcloudDocumentTextRecognizer
:سويفت
let vision = Vision.vision() let textRecognizer = vision.cloudDocumentTextRecognizer() // Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages let options = VisionCloudDocumentTextRecognizerOptions() options.languageHints = ["en", "hi"] let textRecognizer = vision.cloudDocumentTextRecognizer(options: options)
ج موضوعية
FIRVision *vision = [FIRVision vision]; FIRVisionDocumentTextRecognizer *textRecognizer = [vision cloudDocumentTextRecognizer]; // Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages FIRVisionCloudDocumentTextRecognizerOptions *options = [[FIRVisionCloudDocumentTextRecognizerOptions alloc] init]; options.languageHints = @[@"en", @"hi"]; FIRVisionDocumentTextRecognizer *textRecognizer = [vision cloudDocumentTextRecognizerWithOptions: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;
- إذا لزم الأمر، قم بتدوير الصورة بحيث تكون خاصية
- ثم قم بتمرير الصورة إلى طريقة
process(_:completion:)
:سويفت
textRecognizer.process(visionImage) { result, error in guard error == nil, let result = result else { // ... return } // Recognized text }
ج موضوعية
[textRecognizer processImage:image completion:^(FIRVisionDocumentText *_Nullable result, NSError *_Nullable error) { if (error != nil || result == nil) { // ... return; } // Recognized text }];
2. استخرج النص من كتل النص التي تم التعرف عليها
إذا نجحت عملية التعرف على النص، فسوف تقوم بإرجاع كائنVisionDocumentText
. يحتوي كائن VisionDocumentText
على النص الكامل الذي تم التعرف عليه في الصورة وتسلسل هرمي للكائنات التي تعكس بنية المستند الذي تم التعرف عليه: بالنسبة لكل كائن VisionDocumentTextBlock
و VisionDocumentTextParagraph
و VisionDocumentTextWord
و VisionDocumentTextSymbol
، يمكنك التعرف على النص في المنطقة والإحداثيات المحيطة بالمنطقة.
على سبيل المثال:
سويفت
let resultText = result.text for block in result.blocks { let blockText = block.text let blockConfidence = block.confidence let blockRecognizedLanguages = block.recognizedLanguages let blockBreak = block.recognizedBreak let blockCornerPoints = block.cornerPoints let blockFrame = block.frame for paragraph in block.paragraphs { let paragraphText = paragraph.text let paragraphConfidence = paragraph.confidence let paragraphRecognizedLanguages = paragraph.recognizedLanguages let paragraphBreak = paragraph.recognizedBreak let paragraphCornerPoints = paragraph.cornerPoints let paragraphFrame = paragraph.frame for word in paragraph.words { let wordText = word.text let wordConfidence = word.confidence let wordRecognizedLanguages = word.recognizedLanguages let wordBreak = word.recognizedBreak let wordCornerPoints = word.cornerPoints let wordFrame = word.frame for symbol in word.symbols { let symbolText = symbol.text let symbolConfidence = symbol.confidence let symbolRecognizedLanguages = symbol.recognizedLanguages let symbolBreak = symbol.recognizedBreak let symbolCornerPoints = symbol.cornerPoints let symbolFrame = symbol.frame } } } }
ج موضوعية
NSString *resultText = result.text; for (FIRVisionDocumentTextBlock *block in result.blocks) { NSString *blockText = block.text; NSNumber *blockConfidence = block.confidence; NSArray<FIRVisionTextRecognizedLanguage *> *blockRecognizedLanguages = block.recognizedLanguages; FIRVisionTextRecognizedBreak *blockBreak = block.recognizedBreak; CGRect blockFrame = block.frame; for (FIRVisionDocumentTextParagraph *paragraph in block.paragraphs) { NSString *paragraphText = paragraph.text; NSNumber *paragraphConfidence = paragraph.confidence; NSArray<FIRVisionTextRecognizedLanguage *> *paragraphRecognizedLanguages = paragraph.recognizedLanguages; FIRVisionTextRecognizedBreak *paragraphBreak = paragraph.recognizedBreak; CGRect paragraphFrame = paragraph.frame; for (FIRVisionDocumentTextWord *word in paragraph.words) { NSString *wordText = word.text; NSNumber *wordConfidence = word.confidence; NSArray<FIRVisionTextRecognizedLanguage *> *wordRecognizedLanguages = word.recognizedLanguages; FIRVisionTextRecognizedBreak *wordBreak = word.recognizedBreak; CGRect wordFrame = word.frame; for (FIRVisionDocumentTextSymbol *symbol in word.symbols) { NSString *symbolText = symbol.text; NSNumber *symbolConfidence = symbol.confidence; NSArray<FIRVisionTextRecognizedLanguage *> *symbolRecognizedLanguages = symbol.recognizedLanguages; FIRVisionTextRecognizedBreak *symbolBreak = symbol.recognizedBreak; CGRect symbolFrame = symbol.frame; } } } }
الخطوات التالية
- قبل أن تقوم بنشر تطبيق يستخدم Cloud API في الإنتاج، يجب عليك اتخاذ بعض الخطوات الإضافية لمنع وتخفيف تأثير الوصول غير المصرح به إلى API .