يمكنك استخدام Firebase ML للتعرّف على النص في الصور. تتضمّن حزمة Firebase ML واجهة برمجة تطبيقات للأغراض العامة مناسبة للتعرّف على النص في الصور، مثل نص إشارة شارع، وواجهة برمجة تطبيقات محسَّنة للتعرّف على نص المستندات.
قبل البدء
- إذا لم يسبق لك إجراء ذلك، أضِف Firebase إلى مشروع Android.
-
في ملف Gradle للوحدة (على مستوى التطبيق)
(عادةً
<project>/<app-module>/build.gradle.kts
أو<project>/<app-module>/build.gradle
)، أضِف الاعتمادية لمكتبة Firebase ML Vision لنظام التشغيل Android. ننصحك باستخدام Firebase Android BoM للتحكّم في إصدارات المكتبة.dependencies { // Import the BoM for the Firebase platform implementation(platform("com.google.firebase:firebase-bom:34.0.0")) // Add the dependency for the Firebase ML Vision library // When using the BoM, you don't specify versions in Firebase library dependencies implementation 'com.google.firebase:firebase-ml-vision' }
باستخدام Firebase Android BoM، سيستخدم تطبيقك دائمًا إصدارات متوافقة من مكتبات Firebase Android.
(بديل) أضِف تبعيات مكتبة Firebase بدون استخدام BoM
إذا اخترت عدم استخدام Firebase BoM، عليك تحديد إصدار كل مكتبة من مكتبات Firebase في سطر التبعية الخاص بها.
يُرجى العِلم أنّه في حال استخدام مكتبات Firebase BoMمتعدّدة في تطبيقك، ننصحك بشدة باستخدام BoM لإدارة إصدارات المكتبات، ما يضمن توافق جميع الإصدارات.
dependencies { // Add the dependency for the Firebase ML Vision library // When NOT using the BoM, you must specify versions in Firebase library dependencies implementation 'com.google.firebase:firebase-ml-vision:24.1.0' }
-
إذا لم يسبق لك تفعيل واجهات برمجة التطبيقات المستنِدة إلى السحابة الإلكترونية لمشروعك، عليك إجراء ذلك الآن:
- افتح Firebase ML صفحة واجهات برمجة التطبيقات في وحدة تحكّم Firebase.
-
إذا لم يسبق لك ترقية مشروعك إلى خطة أسعار Blaze بنظام الدفع حسب الاستخدام، انقر على ترقية لإجراء ذلك. (لن يُطلب منك الترقية إلا إذا لم يكن مشروعك مشتركًا في خطة أسعار Blaze).
يمكن للمشاريع التي تستخدم خطة التسعير Blaze فقط استخدام واجهات برمجة التطبيقات المستندة إلى السحابة الإلكترونية.
- إذا لم تكن واجهات برمجة التطبيقات المستندة إلى السحابة الإلكترونية مفعّلة، انقر على تفعيل واجهات برمجة التطبيقات المستندة إلى السحابة الإلكترونية.
أنت الآن جاهز لبدء التعرّف على النص في الصور.
إرشادات حول الصور المدخَلة
-
لكي تتعرّف Firebase ML على النص بدقة، يجب أن تحتوي الصور المدخلة على نص يتم تمثيله بواسطة بيانات وحدات بكسل كافية. من المفترض أن يكون حجم كل حرف 16×16 بكسل على الأقل بالنسبة إلى النصوص اللاتينية. بالنسبة إلى النصوص الصينية واليابانية والكورية، يجب أن يبلغ حجم كل حرف 24 × 24 بكسل. وبالنسبة إلى جميع اللغات، لا تتحسّن الدقة بشكل عام إذا كان حجم الأحرف أكبر من 24 × 24 بكسل.
على سبيل المثال، قد تكون صورة بحجم 640x480 مناسبة لمسح بطاقة عمل ضوئيًا تشغل العرض الكامل للصورة. لمسح مستند ضوئيًا مطبوع على ورق بحجم الرسالة، قد تحتاج إلى صورة بحجم 720x1280 بكسل.
-
يمكن أن يؤدي عدم وضوح الصورة إلى انخفاض دقة التعرّف على النص. إذا لم تحصل على نتائج مقبولة، اطلب من المستخدم إعادة التقاط الصورة.
التعرّف على النص في الصور
للتعرّف على النص في صورة، شغِّل أداة التعرّف على النص كما هو موضّح أدناه.
1. تشغيل أداة التعرّف على النص
للتعرّف على نص في صورة، أنشئ عنصرFirebaseVisionImage
من Bitmap
أو media.Image
أو ByteBuffer
أو مصفوفة بايت أو ملف على الجهاز. بعد ذلك، مرِّر الكائن FirebaseVisionImage
إلى الطريقة processImage
الخاصة بالكائن FirebaseVisionTextRecognizer
.
أنشئ عنصر
FirebaseVisionImage
من صورتك.-
لإنشاء عنصر
FirebaseVisionImage
من عنصرmedia.Image
، مثلاً عند التقاط صورة من كاميرا جهاز، مرِّر عنصرmedia.Image
وزاوية دوران الصورة إلىFirebaseVisionImage.fromMediaImage()
.إذا كنت تستخدم مكتبة CameraX، سيحسب لك الفئتان
OnImageCapturedListener
وImageAnalysis.Analyzer
قيمة الدوران، لذلك ما عليك سوى تحويل الدوران إلى أحد الثوابتROTATION_
في Firebase ML قبل استدعاءFirebaseVisionImage.fromMediaImage()
:Kotlin
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 Vision API // ... } } }
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 Vision API // ... } }
إذا لم تستخدم مكتبة كاميرا تتيح لك معرفة درجة دوران الصورة، يمكنك احتسابها من درجة دوران الجهاز واتجاه مستشعر الكاميرا في الجهاز:
Kotlin
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 }
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; }
بعد ذلك، مرِّر العنصر
media.Image
وقيمة التدوير إلىFirebaseVisionImage.fromMediaImage()
:Kotlin
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
- لإنشاء عنصر
FirebaseVisionImage
من معرّف موارد منتظم (URI) لملف، مرِّر سياق التطبيق ومعرّف الموارد المنتظم (URI) للملف إلىFirebaseVisionImage.fromFilePath()
. ويكون ذلك مفيدًا عند استخدامACTION_GET_CONTENT
intent لطلب أن يختار المستخدم صورة من تطبيق المعرض.Kotlin
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
- لإنشاء عنصر
FirebaseVisionImage
منByteBuffer
أو مصفوفة بايت، عليك أولاً حساب درجة دوران الصورة كما هو موضّح أعلاه بالنسبة إلى الإدخالmedia.Image
.بعد ذلك، أنشئ عنصر
FirebaseVisionImageMetadata
يحتوي على ارتفاع الصورة وعرضها وتنسيق ترميز الألوان وزاوية الدوران:Kotlin
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
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();
استخدِم المخزن المؤقت أو المصفوفة وكائن البيانات الوصفية لإنشاء كائن
FirebaseVisionImage
:Kotlin
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
- لإنشاء كائن
FirebaseVisionImage
من كائنBitmap
، اتّبِع الخطوات التالية:Kotlin
val image = FirebaseVisionImage.fromBitmap(bitmap)
Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Bitmap
في الوضع العمودي، بدون الحاجة إلى تدوير إضافي.
-
احصل على مثيل من
FirebaseVisionTextRecognizer
.Kotlin
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()
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();
أخيرًا، مرِّر الصورة إلى الطريقة
processImage
:Kotlin
val result = detector.processImage(image) .addOnSuccessListener { firebaseVisionText -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
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 // ... } });
2- استخراج النص من كتل النص التي تم التعرّف عليها
في حال نجاح عملية التعرّف على النص، سيتم تمرير عنصرFirebaseVisionText
إلى أداة معالجة النجاح. يحتوي كائن FirebaseVisionText
على النص الكامل الذي تم التعرّف عليه في الصورة، بالإضافة إلى صفر أو أكثر من كائنات TextBlock
.
يمثّل كل TextBlock
كتلة نصية مستطيلة الشكل تحتوي على صفر أو أكثر من عناصر Line
. يحتوي كل كائن Line
على صفر أو أكثر من كائنات Element
التي تمثّل الكلمات والكيانات الشبيهة بالكلمات (التواريخ والأرقام وما إلى ذلك).
بالنسبة إلى كل كائن TextBlock
وLine
وElement
، يمكنك الحصول على النص
الذي تم التعرّف عليه في المنطقة وإحداثيات حدود المنطقة.
على سبيل المثال:
Kotlin
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 } } }
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(); } } }
الخطوات التالية
- قبل نشر تطبيق يستخدم إحدى واجهات 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_
في Firebase ML قبل استدعاءFirebaseVisionImage.fromMediaImage()
:Kotlin
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 Vision API // ... } } }
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 Vision API // ... } }
إذا لم تستخدم مكتبة كاميرا تتيح لك معرفة درجة دوران الصورة، يمكنك احتسابها من درجة دوران الجهاز واتجاه مستشعر الكاميرا في الجهاز:
Kotlin
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 }
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; }
بعد ذلك، مرِّر العنصر
media.Image
وقيمة التدوير إلىFirebaseVisionImage.fromMediaImage()
:Kotlin
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
- لإنشاء عنصر
FirebaseVisionImage
من معرّف موارد منتظم (URI) لملف، مرِّر سياق التطبيق ومعرّف الموارد المنتظم (URI) للملف إلىFirebaseVisionImage.fromFilePath()
. ويكون ذلك مفيدًا عند استخدامACTION_GET_CONTENT
intent لطلب أن يختار المستخدم صورة من تطبيق المعرض.Kotlin
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
- لإنشاء عنصر
FirebaseVisionImage
منByteBuffer
أو مصفوفة بايت، عليك أولاً حساب درجة دوران الصورة كما هو موضّح أعلاه بالنسبة إلى الإدخالmedia.Image
.بعد ذلك، أنشئ عنصر
FirebaseVisionImageMetadata
يحتوي على ارتفاع الصورة وعرضها وتنسيق ترميز الألوان وزاوية الدوران:Kotlin
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
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();
استخدِم المخزن المؤقت أو المصفوفة وكائن البيانات الوصفية لإنشاء كائن
FirebaseVisionImage
:Kotlin
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
- لإنشاء كائن
FirebaseVisionImage
من كائنBitmap
، اتّبِع الخطوات التالية:Kotlin
val image = FirebaseVisionImage.fromBitmap(bitmap)
Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Bitmap
في الوضع العمودي، بدون الحاجة إلى تدوير إضافي.
-
الحصول على مثيل من
FirebaseVisionDocumentTextRecognizer
:Kotlin
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)
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);
أخيرًا، مرِّر الصورة إلى الطريقة
processImage
:Kotlin
detector.processImage(myImage) .addOnSuccessListener { firebaseVisionDocumentText -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
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 // ... } });
2- استخراج النص من كتل النص التي تم التعرّف عليها
في حال نجاح عملية التعرّف على النص، سيتم عرض عنصر
FirebaseVisionDocumentText
. يحتوي عنصر FirebaseVisionDocumentText
على النص الكامل الذي تم التعرّف عليه في الصورة وعلى تسلسل هرمي للعناصر يعكس بنية المستند الذي تم التعرّف عليه:
FirebaseVisionDocumentText.Block
FirebaseVisionDocumentText.Paragraph
FirebaseVisionDocumentText.Word
FirebaseVisionDocumentText.Symbol
بالنسبة إلى كل عنصر من عناصر Block
وParagraph
وWord
وSymbol
، يمكنك الحصول على النص الذي تم التعرّف عليه في المنطقة وإحداثيات حدود المنطقة.
على سبيل المثال:
Kotlin
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 } } } }
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(); } } } }
الخطوات التالية
- قبل نشر تطبيق يستخدم إحدى واجهات Cloud API في مرحلة الإنتاج، عليك اتّخاذ بعض الخطوات الإضافية لمنع تأثير الوصول غير المصرّح به إلى واجهة برمجة التطبيقات والحدّ منه.