يمكنك استخدام حزمة تعلُّم الآلة للتعرّف على النص في الصور. تحتوي ML Kit على تناسب واجهة برمجة التطبيقات للأغراض العامة التعرف على النص في الصور، مثل ونص لافتة الشارع وواجهة برمجة تطبيقات محسنة للتعرف على نصوص المستندات. تحتوي واجهة برمجة التطبيقات للأغراض العامة على نماذج على الجهاز ونماذج مستنِدة إلى السحابة الإلكترونية. لا يتوفر التعرف على نص المستند إلا كنموذج مستند إلى السحابة الإلكترونية. يمكنك الاطّلاع على نظرة عامة لمقارنة السحابة الإلكترونية والنماذج المتوفّرة على الجهاز فقط.
قبل البدء
- إذا لم تكن قد فعلت ذلك بالفعل، إضافة Firebase إلى مشروع Android
- إضافة الموارد التابعة لمكتبات ML Kit على Android إلى الوحدة
(على مستوى التطبيق) ملف Gradle (عادةً
app/build.gradle
):apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' dependencies { // ... implementation 'com.google.firebase:firebase-ml-vision:24.0.3' }
-
إجراء اختياري ولكنّنا ننصح به: إذا كنت تستخدم واجهة برمجة التطبيقات على الجهاز، اضبط
تطبيقًا لتنزيل نموذج تعلُّم الآلة تلقائيًا على الجهاز بعد إنشاء
التطبيقات المثبّتة من متجر Play.
لإجراء ذلك، يُرجى إضافة البيان التالي إلى صفحة تطبيقك. ملف
AndroidManifest.xml
:<application ...> ... <meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="ocr" /> <!-- To use multiple models: android:value="ocr,model2,model3" --> </application>
في حال عدم تفعيل عمليات تنزيل نموذج وقت التثبيت، سيتم تنفيذ تم تنزيله في المرة الأولى التي تُشغِّل فيها أداة الرصد على الجهاز. الطلبات التي تقدّمها قبل اكتمال التنزيل، فلن تظهر أي نتائج. -
إذا أردت استخدام النموذج المستند إلى السحابة الإلكترونية، ولم يسبق لك تفعيل لواجهات برمجة التطبيقات (API) المستندة إلى السحابة الإلكترونية لمشروعك، قم بذلك الآن:
- فتح ML Kit صفحة واجهات برمجة التطبيقات في وحدة تحكُّم Firebase.
-
إذا لم تكن قد أجريت ترقية لمشروعك إلى خطة أسعار Blaze، انقر على يجب الترقية لإجراء ذلك. (ستتم مطالبتك بالترقية فقط إذا كان مشروعك ليس على خطة Blaze).
يمكن للمشروعات على مستوى Blaze فقط استخدام واجهات برمجة التطبيقات المستنِدة إلى السحابة الإلكترونية.
- إذا لم تكن واجهات برمجة التطبيقات المستنِدة إلى السحابة الإلكترونية مُفعَّلة، انقر على تفعيل البيانات المستندة إلى السحابة الإلكترونية. API.
إذا كنت تريد استخدام النموذج على الجهاز فقط، يمكنك تخطّي هذه الخطوة.
أنت الآن جاهز لبدء التعرف على النص في الصور.
إرشادات إدخال الصور
-
لكي تتعرّف أداة تعلّم الآلة على النص بدقة، يجب أن تحتوي الصور المدخلة على نص يتم تمثيله ببيانات بكسل كافية. من الناحية المثالية، للّغة اللاتينية نص، يجب أن يبلغ حجم كل حرف 16×16 بكسل على الأقل. بالنسبة إلى اللغة الصينية، النصوص اليابانية والكورية (المدعومة فقط من خلال واجهات برمجة التطبيقات المستندة إلى السحابة الإلكترونية)، يجب أن يكون حجم الحرف 24×24 بكسل. بالنسبة لجميع اللغات، لا يوجد عمومًا على الدقة المحدد للأحرف الأكبر من 24×24 بكسل.
لذلك، على سبيل المثال، قد تعمل صورة بحجم 640×480 جيدًا لمسح بطاقة عمل ضوئيًا تشغل العرض الكامل للصورة لإجراء مسح ضوئي لمستند مطبوع على ورق بحجم حرف، فقد يلزم صورة 720×1280 بكسل.
-
يمكن أن يؤدي التركيز الضعيف للصورة إلى التأثير سلبًا في دقة التعرّف على النص. إذا لم تكن كذلك والحصول على نتائج مقبولة، فحاول أن تطلب من المستخدم تلخيص الصورة.
-
إذا كنت تتعرف على النص في تطبيق في الوقت الفعلي، فيمكنك أيضًا يريدون في الاعتبار الأبعاد الكلية لصور الإدخال. أصغر يمكن معالجة الصور بشكل أسرع، لذلك لتقليل وقت الاستجابة، التقط الصور درجات دقة أقل (مع الأخذ في الاعتبار متطلبات الدقة المذكورة أعلاه) التأكد من أن النص يشغل أكبر قدر ممكن من الصورة. راجع أيضًا نصائح لتحسين الأداء في الوقت الفعلي.
التعرّف على النص في الصور
للتعرّف على النص في صورة باستخدام نموذج على الجهاز أو نموذج مستند إلى السحابة، تشغيل أداة التعرف على النص كما هو موضح أدناه.
1- تشغيل أداة التعرّف على النص
للتعرّف على نص في صورة، عليك إنشاء عنصرFirebaseVisionImage
.
من Bitmap
أو media.Image
أو ByteBuffer
أو مصفوفة بايت أو ملف على
الجهاز. مرِّر بعد ذلك الكائن FirebaseVisionImage
إلى
طريقة processImage
لـ FirebaseVisionTextRecognizer
.
أنشئ عنصر
FirebaseVisionImage
من صورتك.-
لإنشاء عنصر
FirebaseVisionImage
من كائنmedia.Image
، مثل عند التقاط صورة من كاميرا الجهاز، يُرجى تمرير كائنmedia.Image
تدوير إلىFirebaseVisionImage.fromMediaImage()
.إذا كنت تستخدم CameraX و
OnImageCapturedListener
تحتسب صفوفImageAnalysis.Analyzer
قيمة عرض الإعلانات بالتناوب. لك، لذا ما عليك سوى تحويل الدوران إلى إحدى أدوات تعلّم الآلةROTATION_
ثابت قبل إجراء الطلبFirebaseVisionImage.fromMediaImage()
:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin+KTX
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
إذا لم تكن تستخدم مكتبة كاميرا تمنحك تدوير الصورة، يمكنك من دوران الجهاز واتجاه الكاميرا جهاز الاستشعار في الجهاز:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private int getRotationCompensation(String cameraId, Activity activity, Context context) throws CameraAccessException { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int rotationCompensation = ORIENTATIONS.get(deviceRotation); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin+KTX
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Throws(CameraAccessException::class) private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. val deviceRotation = activity.windowManager.defaultDisplay.rotation var rotationCompensation = ORIENTATIONS.get(deviceRotation) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
بعد ذلك، مرِّر الكائن
media.Image
قيمة التدوير إلىFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- لإنشاء كائن
FirebaseVisionImage
من معرّف موارد منتظم (URI) لملف، مرِّر سياق التطبيق ومعرّف الموارد المنتظم (URI) للملفFirebaseVisionImage.fromFilePath()
يكون ذلك مفيدًا عندما يجب استخدام هدفACTION_GET_CONTENT
لتطلب من المستخدم الاختيار. صورة من تطبيق المعرض الخاص به.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin+KTX
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- لإنشاء عنصر
FirebaseVisionImage
منByteBuffer
أو صفيف بايت، احسب الصورة أولاً تدوير كما هو موضح أعلاه لإدخالmedia.Image
.بعد ذلك، يمكنك إنشاء كائن
FirebaseVisionImageMetadata
. يتضمن ارتفاع الصورة وعرضها وتنسيق ترميز الألوان لها وتدوير:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin+KTX
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
استخدم المخزن المؤقت أو الصفيفة وكائن البيانات الوصفية لإنشاء كائن
FirebaseVisionImage
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin+KTX
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- لإنشاء عنصر
FirebaseVisionImage
من كائنBitmap
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
مستقيمًا، دون الحاجة إلى دوران إضافي.
-
الحصول على مثال
FirebaseVisionTextRecognizer
لاستخدام النموذج على الجهاز فقط:
Java
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() .getOnDeviceTextRecognizer();
Kotlin+KTX
val detector = FirebaseVision.getInstance() .onDeviceTextRecognizer
لاستخدام النموذج المستند إلى السحابة الإلكترونية:
Java
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() .getCloudTextRecognizer(); // Or, to change the default settings: // FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() // .getCloudTextRecognizer(options);
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages FirebaseVisionCloudTextRecognizerOptions options = new FirebaseVisionCloudTextRecognizerOptions.Builder() .setLanguageHints(Arrays.asList("en", "hi")) .build();
Kotlin+KTX
val detector = FirebaseVision.getInstance().cloudTextRecognizer // Or, to change the default settings: // val detector = FirebaseVision.getInstance().getCloudTextRecognizer(options)
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages val options = FirebaseVisionCloudTextRecognizerOptions.Builder() .setLanguageHints(listOf("en", "hi")) .build()
أخيرًا، ضع الصورة في طريقة
processImage
:Java
Task<FirebaseVisionText> result = detector.processImage(image) .addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() { @Override public void onSuccess(FirebaseVisionText firebaseVisionText) { // Task completed successfully // ... } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin+KTX
val result = detector.processImage(image) .addOnSuccessListener { firebaseVisionText -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
2- استخراج النص من مجموعات النصوص التي تم التعرّف عليها
إذا نجحت عملية التعرّف على النص، فسيتم سيتم تمرير الكائنFirebaseVisionText
بنجاح.
المستمع. يحتوي كائن FirebaseVisionText
على النص الكامل الذي تم التعرّف عليه في
الصورة وصفر أو أكثر من عناصر TextBlock
.
يمثل كل TextBlock
كتلة نص مستطيلة تحتوي على صفر أو
المزيد من عناصر Line
. كل عنصر Line
يحتوي على صفر أو أكثر
كائنات Element
، التي تمثل كلمات وتشبه الكلمات
الكيانات (التواريخ والأرقام وما إلى ذلك).
بالنسبة إلى كل كائن TextBlock
وLine
وElement
، يمكنك الحصول على النص
المعترف بها في المنطقة وإحداثيات الحدود للمنطقة.
على سبيل المثال:
Java
String resultText = result.getText(); for (FirebaseVisionText.TextBlock block: result.getTextBlocks()) { String blockText = block.getText(); Float blockConfidence = block.getConfidence(); List<RecognizedLanguage> blockLanguages = block.getRecognizedLanguages(); Point[] blockCornerPoints = block.getCornerPoints(); Rect blockFrame = block.getBoundingBox(); for (FirebaseVisionText.Line line: block.getLines()) { String lineText = line.getText(); Float lineConfidence = line.getConfidence(); List<RecognizedLanguage> lineLanguages = line.getRecognizedLanguages(); Point[] lineCornerPoints = line.getCornerPoints(); Rect lineFrame = line.getBoundingBox(); for (FirebaseVisionText.Element element: line.getElements()) { String elementText = element.getText(); Float elementConfidence = element.getConfidence(); List<RecognizedLanguage> elementLanguages = element.getRecognizedLanguages(); Point[] elementCornerPoints = element.getCornerPoints(); Rect elementFrame = element.getBoundingBox(); } } }
Kotlin+KTX
val resultText = result.text for (block in result.textBlocks) { val blockText = block.text val blockConfidence = block.confidence val blockLanguages = block.recognizedLanguages val blockCornerPoints = block.cornerPoints val blockFrame = block.boundingBox for (line in block.lines) { val lineText = line.text val lineConfidence = line.confidence val lineLanguages = line.recognizedLanguages val lineCornerPoints = line.cornerPoints val lineFrame = line.boundingBox for (element in line.elements) { val elementText = element.text val elementConfidence = element.confidence val elementLanguages = element.recognizedLanguages val elementCornerPoints = element.cornerPoints val elementFrame = element.boundingBox } } }
نصائح لتحسين الأداء في الوقت الفعلي
إذا أردت استخدام النموذج على الجهاز فقط للتعرّف على النص في الوقت الفعلي التطبيق، يُرجى اتباع الإرشادات التالية لتحقيق أفضل معدلات عرض الإطارات:
- تقييد الطلبات إلى أداة التعرّف على النص. إذا أصبح إطار فيديو جديد يكون متاحًا أثناء تشغيل أداة التعرّف على النص، أفلِت الإطار.
- إذا كنت تستخدم ناتج أداة التعرف على النص لتراكب الرسومات على الصورة المدخلة، والحصول أولاً على النتيجة من ML Kit، ثم عرض الصورة وتراكبها في خطوة واحدة. ومن خلال القيام بذلك، يمكنك العرض على سطح الشاشة مرة واحدة فقط لكل إطار إدخال
-
في حال استخدام واجهة برمجة التطبيقات Camera2 API، يمكنك التقاط الصور في تنسيق
ImageFormat.YUV_420_888
إذا كنت تستخدم واجهة برمجة التطبيقات للكاميرا القديمة، يمكنك التقاط الصور في تنسيق
ImageFormat.NV21
- يمكنك التقاط صور بدقة أقل. ومع ذلك، ضع في اعتبارك أيضًا متطلبات أبعاد الصورة في واجهة برمجة التطبيقات هذه.
الخطوات التالية
- قبل نشر تطبيق يستخدم Cloud API في قناة الإصدار العلني، يجب إجراء بعض الخطوات الإضافية لمنع وتخفيف تأثير الوصول غير المُصرح به إلى واجهة برمجة التطبيقات.
التعرّف على النص في صور المستندات
للتعرف على نص المستند، قم بتهيئة وتشغيل أداة التعرّف على النص في المستند كما هو موضّح أدناه.
وتوفر واجهة برمجة التطبيقات للتعرف على نص المستندات، الموضحة أدناه، واجهة
أن يكون أكثر ملاءمة للعمل على صور المستندات. ومع ذلك،
إذا كنت تفضّل استخدام الواجهة التي توفّرها واجهة برمجة التطبيقات FirebaseVisionTextRecognizer
يمكنك استخدامه بدلاً من ذلك لمسح المستندات ضوئيًا من خلال
ضبط إعدادات النصوص على السحابة الإلكترونية
أداة التعرف على استخدام نموذج النص الكثيف.
لاستخدام واجهة برمجة تطبيقات التعرف على النص في المستندات:
1- تشغيل أداة التعرّف على النص
للتعرّف على النص في صورة، أنشِئ كائنFirebaseVisionImage
من أي مما يلي:
Bitmap
أو media.Image
أو ByteBuffer
أو مصفوفة بايت أو ملف على الجهاز.
مرِّر بعد ذلك الكائن FirebaseVisionImage
إلى
طريقة processImage
لـ FirebaseVisionDocumentTextRecognizer
.
أنشئ عنصر
FirebaseVisionImage
من صورتك.-
لإنشاء عنصر
FirebaseVisionImage
من كائنmedia.Image
، مثل عند التقاط صورة من كاميرا الجهاز، يُرجى تمرير كائنmedia.Image
تدوير إلىFirebaseVisionImage.fromMediaImage()
.إذا كنت تستخدم CameraX و
OnImageCapturedListener
تحتسب صفوفImageAnalysis.Analyzer
قيمة عرض الإعلانات بالتناوب. لك، لذا ما عليك سوى تحويل الدوران إلى إحدى أدوات تعلّم الآلةROTATION_
ثابت قبل إجراء الطلبFirebaseVisionImage.fromMediaImage()
:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin+KTX
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
إذا لم تكن تستخدم مكتبة كاميرا تمنحك تدوير الصورة، يمكنك من دوران الجهاز واتجاه الكاميرا جهاز الاستشعار في الجهاز:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private int getRotationCompensation(String cameraId, Activity activity, Context context) throws CameraAccessException { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int rotationCompensation = ORIENTATIONS.get(deviceRotation); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin+KTX
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Throws(CameraAccessException::class) private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. val deviceRotation = activity.windowManager.defaultDisplay.rotation var rotationCompensation = ORIENTATIONS.get(deviceRotation) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
بعد ذلك، مرِّر الكائن
media.Image
قيمة التدوير إلىFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- لإنشاء كائن
FirebaseVisionImage
من معرّف موارد منتظم (URI) لملف، مرِّر سياق التطبيق ومعرّف الموارد المنتظم (URI) للملفFirebaseVisionImage.fromFilePath()
يكون ذلك مفيدًا عندما يجب استخدام هدفACTION_GET_CONTENT
لتطلب من المستخدم الاختيار. صورة من تطبيق المعرض الخاص به.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin+KTX
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- لإنشاء عنصر
FirebaseVisionImage
منByteBuffer
أو صفيف بايت، احسب الصورة أولاً تدوير كما هو موضح أعلاه لإدخالmedia.Image
.بعد ذلك، يمكنك إنشاء كائن
FirebaseVisionImageMetadata
. يتضمن ارتفاع الصورة وعرضها وتنسيق ترميز الألوان لها وتدوير:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin+KTX
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
استخدم المخزن المؤقت أو الصفيفة وكائن البيانات الوصفية لإنشاء كائن
FirebaseVisionImage
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin+KTX
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- لإنشاء عنصر
FirebaseVisionImage
من كائنBitmap
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
مستقيمًا، دون الحاجة إلى دوران إضافي.
-
الحصول على مثال
FirebaseVisionDocumentTextRecognizer
:Java
FirebaseVisionDocumentTextRecognizer detector = FirebaseVision.getInstance() .getCloudDocumentTextRecognizer();
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages FirebaseVisionCloudDocumentRecognizerOptions options = new FirebaseVisionCloudDocumentRecognizerOptions.Builder() .setLanguageHints(Arrays.asList("en", "hi")) .build(); FirebaseVisionDocumentTextRecognizer detector = FirebaseVision.getInstance() .getCloudDocumentTextRecognizer(options);
Kotlin+KTX
val detector = FirebaseVision.getInstance() .cloudDocumentTextRecognizer
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages val options = FirebaseVisionCloudDocumentRecognizerOptions.Builder() .setLanguageHints(listOf("en", "hi")) .build() val detector = FirebaseVision.getInstance() .getCloudDocumentTextRecognizer(options)
أخيرًا، ضع الصورة في طريقة
processImage
:Java
detector.processImage(myImage) .addOnSuccessListener(new OnSuccessListener<FirebaseVisionDocumentText>() { @Override public void onSuccess(FirebaseVisionDocumentText result) { // Task completed successfully // ... } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin+KTX
detector.processImage(myImage) .addOnSuccessListener { firebaseVisionDocumentText -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
2- استخراج النص من مجموعات النصوص التي تم التعرّف عليها
إذا نجحت عملية التعرف على النص، فستعرض
FirebaseVisionDocumentText
. حاسمة
يحتوي كائن FirebaseVisionDocumentText
على النص الكامل الذي تم التعرّف عليه في
وتدرج هرمي للكائنات التي تعكس بنية
المستند:
FirebaseVisionDocumentText.Block
FirebaseVisionDocumentText.Paragraph
FirebaseVisionDocumentText.Word
FirebaseVisionDocumentText.Symbol
بالنسبة إلى كل عناصر Block
وParagraph
وWord
وSymbol
، يمكنك الحصول على
للنص المعترف به في المنطقة وإحداثيات الإحاطة بهذه المنطقة.
على سبيل المثال:
Java
String resultText = result.getText(); for (FirebaseVisionDocumentText.Block block: result.getBlocks()) { String blockText = block.getText(); Float blockConfidence = block.getConfidence(); List<RecognizedLanguage> blockRecognizedLanguages = block.getRecognizedLanguages(); Rect blockFrame = block.getBoundingBox(); for (FirebaseVisionDocumentText.Paragraph paragraph: block.getParagraphs()) { String paragraphText = paragraph.getText(); Float paragraphConfidence = paragraph.getConfidence(); List<RecognizedLanguage> paragraphRecognizedLanguages = paragraph.getRecognizedLanguages(); Rect paragraphFrame = paragraph.getBoundingBox(); for (FirebaseVisionDocumentText.Word word: paragraph.getWords()) { String wordText = word.getText(); Float wordConfidence = word.getConfidence(); List<RecognizedLanguage> wordRecognizedLanguages = word.getRecognizedLanguages(); Rect wordFrame = word.getBoundingBox(); for (FirebaseVisionDocumentText.Symbol symbol: word.getSymbols()) { String symbolText = symbol.getText(); Float symbolConfidence = symbol.getConfidence(); List<RecognizedLanguage> symbolRecognizedLanguages = symbol.getRecognizedLanguages(); Rect symbolFrame = symbol.getBoundingBox(); } } } }
Kotlin+KTX
val resultText = result.text for (block in result.blocks) { val blockText = block.text val blockConfidence = block.confidence val blockRecognizedLanguages = block.recognizedLanguages val blockFrame = block.boundingBox for (paragraph in block.paragraphs) { val paragraphText = paragraph.text val paragraphConfidence = paragraph.confidence val paragraphRecognizedLanguages = paragraph.recognizedLanguages val paragraphFrame = paragraph.boundingBox for (word in paragraph.words) { val wordText = word.text val wordConfidence = word.confidence val wordRecognizedLanguages = word.recognizedLanguages val wordFrame = word.boundingBox for (symbol in word.symbols) { val symbolText = symbol.text val symbolConfidence = symbol.confidence val symbolRecognizedLanguages = symbol.recognizedLanguages val symbolFrame = symbol.boundingBox } } } }
الخطوات التالية
- قبل نشر تطبيق يستخدم Cloud API في قناة الإصدار العلني، يجب إجراء بعض الخطوات الإضافية لمنع وتخفيف تأثير الوصول غير المُصرح به إلى واجهة برمجة التطبيقات.