إنشاء تطبيق Android للتعرف على النص في 10 دقائق. كود الرؤية المحمول

نسخة فيديو من البرنامج التعليمي



يوفر التعرف البصري على الأحرف ( OCR ) للكمبيوتر القدرة على قراءة النص في صورة ما ، مما يسمح للتطبيقات بفهم العلامات أو المقالات أو النشرات أو صفحات النص أو القوائم أو أي شيء في شكل نص. توفر Mobile Vision Text API لمطوري Android ميزة OCR قوية وموثوقة تدعم معظم أجهزة Android ولا تزيد من حجم تطبيقك.


في هذا البرنامج التعليمي ، ستقوم بإنشاء تطبيق يتم فيه التعرف على كل النص الذي يقع في الإطار وتشغيله أثناء عملية تسجيل الفيديو.


نشرنا أيضًا مقالات حول ميزات Mobile Vision الأخرى:



يمكن تنزيل شفرة المصدر هنا .


أو استنساخ مستودع GitHub من سطر الأوامر:


 $ git clone https://github.com/googlesamples/android-vision.git 

يحتوي مستودع visionSamples على العديد من المشاريع visionSamples المتعلقة بـ Mobile Vision . يتم استخدام اثنين فقط في هذا الدرس:


  • ocr-codelab / ocr-reader-start هو الرمز الأولي الذي ستستخدمه في هذا الدرس.
  • ocr-codelab / ocr-reader-complete - الكود الكامل للتطبيق النهائي. يمكنك استخدامه لاستكشاف الأخطاء وإصلاحها أو الانتقال مباشرة إلى تطبيق العمل.

تحديث خدمات Google Play


قد تحتاج إلى ترقية الإصدار المثبت من Google Repository لاستخدام Mobile Vision Text API .


افتح Android Studio وافتح SDK Manager :




تأكد من تحديث Google Repository . يجب أن يكون الإصدار 26 على الأقل.




أضف تبعية لخدمات Google Play وقم بإنشاء تطبيق قاذفة


الآن يمكنك فتح مشروع المبتدئين:


  1. اختر دليل التشغيل ocr-reader من الكود الذي تم تنزيله ( File > Open > ocr-codelab/ocr-reader-start ).


  2. أضف تبعية Google Play Services إلى التطبيق. بدون هذه التبعية ، لن تكون Text API متاحة.



قد يشير المشروع إلى عدم وجود ملف عدد صحيح / google_play_services_version ويعطي خطأ. هذا أمر طبيعي ، سنقوم بإصلاحه في الخطوة التالية.


افتح ملف build.gradle في وحدة app وقم بتغيير كتلة التبعية لتضمين تبعية play-services-vision هناك. عندما يكون كل شيء جاهزًا ، يجب أن يبدو الملف كما يلي:


 dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:support-v4:26.1.0' implementation 'com.android.support:design:26.1.0' implementation 'com.google.android.gms:play-services-vision:15.0.0' } 

  1. انقر زر مزامنة Gradle .


  2. انقر زر البدء.



بعد بضع ثوانٍ ، سترى شاشة "قراءة النص" ، ولكن هذه مجرد شاشة سوداء.




لا شيء يحدث الآن لأنه لم CameraSource تهيئة CameraSource . فلنفعل ذلك.


إذا لم تنجح ، يمكنك فتح مشروع ocr-reader-complete وتأكد من أنه يعمل بشكل صحيح. هذا المشروع هو نسخة جاهزة من الدرس ، وإذا لم يعمل هذا الإصدار ، فيجب عليك التحقق من أن كل شيء على ما يرام مع إعدادات جهازك وإعدادات Android Studio .


تكوين TextRecognizer و CameraSource


للبدء ، سنقوم بإنشاء TextRecognizer بنا. يعالج كائن الكاشف الصور ويحدد النص الذي يظهر داخلها. بعد التهيئة ، يمكن استخدام TextRecognizer للكشف عن النص في جميع أنواع الصور. ابحث عن طريقة createCameraSource وأنشئ TextRecognizer :


OcrCaptureActivity.java


 private void createCameraSource(boolean autoFocus, boolean useFlash) { Context context = getApplicationContext(); // TODO: Create the TextRecognizer TextRecognizer textRecognizer = new TextRecognizer.Builder(context).build(); // TODO: Set the TextRecognizer's Processor. // TODO: Check if the TextRecognizer is operational. // TODO: Create the mCameraSource using the TextRecognizer. } 

TextRecognizer الآن جاهزًا TextRecognizer . ومع ذلك ، قد لا تعمل بعد. إذا لم يكن الجهاز يحتوي على ذاكرة كافية أو تعذر على Google Play Services تحميل تبعيات OCR ، فلن يعمل كائن TextRecognizer . قبل أن نبدأ في استخدامه للتعرف على النص ، يجب علينا التحقق من أنه جاهز. سنضيف هذا التحقق createCameraSource بعد تهيئة TextRecognizer :


OcrCaptureActivity.java


 // TODO: Check if the TextRecognizer is operational. if (!textRecognizer.isOperational()) { Log.w(TAG, "Detector dependencies are not yet available."); // Check for low storage. If there is low storage, the native library will not be // downloaded, so detection will not become operational. IntentFilter lowstorageFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW); boolean hasLowStorage = registerReceiver(null, lowstorageFilter) != null; if (hasLowStorage) { Toast.makeText(this, R.string.low_storage_error, Toast.LENGTH_LONG).show(); Log.w(TAG, getString(R.string.low_storage_error)); } } 

الآن بعد أن TextRecognizer أن TextRecognizer جاهز للاستخدام ، يمكننا استخدامه للتعرف على الإطارات الفردية. لكننا نريد أن نفعل شيئًا أكثر إثارة للاهتمام: اقرأ النص في وضع الفيديو. للقيام بذلك ، سنقوم بإنشاء مصدر CameraSource مسبقًا للتحكم في الكاميرا. نحن بحاجة إلى تعيين دقة عالية للتصوير وتمكين التركيز التلقائي للتعامل مع مهمة التعرف على النص الصغير. إذا كنت متأكدًا من أن المستخدمين سينظرون إلى كتل نصية كبيرة ، على سبيل المثال الإشارات ، فيمكنك استخدام دقة أقل ، ومن ثم ستكون معالجة الإطار أسرع:


OcrCaptureActivity.java


 // TODO: Create the cameraSource using the TextRecognizer. cameraSource = new CameraSource.Builder(getApplicationContext(), textRecognizer) .setFacing(CameraSource.CAMERA_FACING_BACK) .setRequestedPreviewSize(1280, 1024) .setRequestedFps(15.0f) .setFlashMode(useFlash ? Camera.Parameters.FLASH_MODE_TORCH : null) .setFocusMode(autoFocus ? Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO : null) .build(); 

إليك ما يجب أن تبدو عليه طريقة createCameraSource عند الانتهاء:


OcrCaptureActivity.java


 private void createCameraSource(boolean autoFocus, boolean useFlash) { Context context = getApplicationContext(); // Create the TextRecognizer TextRecognizer textRecognizer = new TextRecognizer.Builder(context).build(); // TODO: Set the TextRecognizer's Processor. // Check if the TextRecognizer is operational. if (!textRecognizer.isOperational()) { Log.w(TAG, "Detector dependencies are not yet available."); // Check for low storage. If there is low storage, the native library will not be // downloaded, so detection will not become operational. IntentFilter lowstorageFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW); boolean hasLowStorage = registerReceiver(null, lowstorageFilter) != null; if (hasLowStorage) { Toast.makeText(this, R.string.low_storage_error, Toast.LENGTH_LONG).show(); Log.w(TAG, getString(R.string.low_storage_error)); } } // Create the cameraSource using the TextRecognizer. cameraSource = new CameraSource.Builder(getApplicationContext(), textRecognizer) .setFacing(CameraSource.CAMERA_FACING_BACK) .setRequestedPreviewSize(1280, 1024) .setRequestedFps(15.0f) .setFlashMode(useFlash ? Camera.Parameters.FLASH_MODE_TORCH : null) .setFocusMode(autoFocus ? Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO : null) .build(); } 

إذا قمت بتشغيل التطبيق ، سترى أن الفيديو قد بدأ! ولكن لمعالجة الصور من الكاميرا ، نحتاج إلى إضافة هذا TODO الأخير لإنشاء createCameraSource : إنشاء Processor لمعالجة النص عند وصوله.


إنشاء OcrDetectorProcessor


يمكن TextRecognizer الآن اكتشاف النص على الإطارات الفردية باستخدام طريقة الاكتشاف في TextRecognizer . لذا يمكنك العثور على نص ، على سبيل المثال ، في صورة فوتوغرافية. ولكن لقراءة النص مباشرة أثناء تصوير الفيديو ، تحتاج إلى تنفيذ Processor بمعالجة النص بمجرد ظهوره على الشاشة.


انتقل إلى فئة OcrDetectorProcessor بتطبيق واجهة Detector.Processor :


OcrDetectorProcessor.java


 public class OcrDetectorProcessor implements Detector.Processor<TextBlock> { private GraphicOverlay<OcrGraphic> graphicOverlay; OcrDetectorProcessor(GraphicOverlay<OcrGraphic> ocrGraphicOverlay) { graphicOverlay = ocrGraphicOverlay; } } 

لتنفيذ هذه الواجهة ، تحتاج إلى تجاوز طريقتين. الأول ، يتلقى تلقي receiveDetections ، يتلقى TextBlocks من TextRecognizer عند اكتشافها. يتم استخدام الإصدار الثاني لإطلاق الموارد عند تدمير TextRecognizer . في هذه الحالة ، نحتاج فقط إلى مسح اللوحة الرسومية ، مما سيؤدي إلى حذف جميع كائنات OcrGraphic .


سنحصل على TextBlocks OcrGraphic كائنات OcrGraphic لكل كتلة نصية يكتشفها المعالج. نقوم بتطبيق منطق رسمهم في الخطوة التالية.


OcrDetectorProcessor.java


 @Override public void receiveDetections(Detector.Detections<TextBlock> detections) { graphicOverlay.clear(); SparseArray<TextBlock> items = detections.getDetectedItems(); for (int i = 0; i < items.size(); ++i) { TextBlock item = items.valueAt(i); if (item != null && item.getValue() != null) { Log.d("Processor", "Text detected! " + item.getValue()); OcrGraphic graphic = new OcrGraphic(graphicOverlay, item); graphicOverlay.add(graphic); } } } @Override public void release() { graphicOverlay.clear(); } 

الآن بعد أن أصبح المعالج جاهزًا ، نحتاج إلى تكوين textRecognizer لاستخدامه. ارجع إلى آخر TODO المتبقي في طريقة OcrCaptureActivity في OcrCaptureActivity :


OcrCaptureActivity.java


 // Create the TextRecognizer TextRecognizer textRecognizer = new TextRecognizer.Builder(context).build(); // TODO: Set the TextRecognizer's Processor. textRecognizer.setProcessor(new OcrDetectorProcessor(graphicOverlay)); 

الآن قم بتشغيل التطبيق. عند هذه النقطة ، عند تحريك الكاميرا فوق النص ، سترى رسائل التصحيح "تم الكشف عن النص!" في Android Monitor Logcat ! لكن هذه ليست طريقة بصرية للغاية لتصور ما تراه TextRecognizer ، أليس كذلك؟


في الخطوة التالية ، سنرسم هذا النص على الشاشة.


رسم النص على الشاشة


دعونا نطبق طريقة draw في OcrGraphic . نحن بحاجة إلى فهم ما إذا كان هناك نص في الصورة ، وتحويل إحداثيات حدودها إلى إطارات قماشية ، ثم رسم كل من الحدود والنص.


OcrGraphic.java


 @Override public void draw(Canvas canvas) { // TODO: Draw the text onto the canvas. if (text == null) { return; } // Draws the bounding box around the TextBlock. RectF rect = new RectF(text.getBoundingBox()); rect = translateRect(rect); canvas.drawRect(rect, rectPaint); // Render the text at the bottom of the box. canvas.drawText(text.getValue(), rect.left, rect.bottom, textPaint); } 

قم بتشغيل التطبيق واختبره على هذا النموذج النصي:



يجب أن ترى ظهور إطار على الشاشة يحتوي على نص! يمكنك اللعب بلون النص باستخدام TEXT_COLOR .


ماذا عن هذا؟



يبدو الإطار حول النص صحيحًا ، ولكن النص في أسفله.




وذلك لأن المحرك ينقل كل النص الذي يتعرف عليه في TextBlock واحدة ، حتى إذا رأى جملة مقسمة إلى عدة أسطر. إذا كنت بحاجة إلى الحصول على العرض بالكامل ، فهذا مناسب جدًا. ولكن ماذا لو كنت تريد أن تعرف أين يقع كل سطر فردي من النص؟


يمكنك الحصول على Lines من TextBlock عن طريق استدعاء getComponents ، ومن ثم ، من خلال الفرز عبر كل سطر ، يمكنك بسهولة الحصول على موقعه والنص داخله. هذا يسمح لك برسم النص في المكان الذي يظهر فيه حقًا.


OcrGraphic.java


 @Override public void draw(Canvas canvas) { // TODO: Draw the text onto the canvas. if (text == null) { return; } // Draws the bounding box around the TextBlock. RectF rect = new RectF(text.getBoundingBox()); rect = translateRect(rect); canvas.drawRect(rect, rectPaint); // Break the text into multiple lines and draw each one according to its own bounding box. List<? extends Text> textComponents = text.getComponents(); for(Text currentText : textComponents) { float left = translateX(currentText.getBoundingBox().left); float bottom = translateY(currentText.getBoundingBox().bottom); canvas.drawText(currentText.getValue(), left, bottom, textPaint); } } 

حاول هذا النص مرة أخرى:



عظيم! يمكنك حتى تقسيم النص الموجود إلى مكونات أصغر ، بناءً على احتياجاتك. يمكنك استدعاء getComponents في كل سطر والحصول على Elements (الكلمات اللاتينية). من الممكن تكوين textSize بحيث يأخذ النص مساحة كبيرة مثل النص الفعلي على الشاشة.




قراءة النص عند النقر عليه


الآن يتم تحويل النص من الكاميرا إلى خطوط منظمة ، ويتم عرض هذه الخطوط على الشاشة. فلنفعل شيئًا آخر معهم.


باستخدام TextToSpeech API المدمج في Android والطريقة OcrGraphic في OcrGraphic ، يمكننا تعليم التطبيق للتحدث بصوت عالٍ عند النقر على النص.


أولاً ، دعنا نطبق الأسلوب contains OcrGraphic . نحتاج فقط إلى التحقق مما إذا كانت إحداثيات y وص ضمن حدود النص المعروض.
OcrGraphic.java


 public boolean contains(float x, float y) { // TODO: Check if this graphic's text contains this point. if (text == null) { return false; } RectF rect = new RectF(text.getBoundingBox()); rect = translateRect(rect); return rect.contans(x, y); } 

قد تلاحظ أن هناك الكثير من القواسم المشتركة مع طريقة Draw ! في هذا المشروع ، يجب أن تكون قادرًا على إعادة استخدام الرمز ، ولكن هنا نترك كل شيء كما هو فقط من أجل المثال.


الآن دعنا ننتقل إلى طريقة onTap في OcrCaptureActivity ومعالجة النقر على النص ، إذا كان هناك واحد في هذا المكان.


OcrCaptureActivity.java


 private boolean onTap(float rawX, float rawY) { // TODO: Speak the text when the user taps on screen. OcrGraphic graphic = graphicOverlay.getGraphicAtLocation(rawX, rawY); TextBlock text = null; if (graphic != null) { text = graphic.getTextBlock(); if (text != null && text.getValue() != null) { Log.d(TAG, "text data is being spoken! " + text.getValue()); // TODO: Speak the string. } else { Log.d(TAG, "text data is null"); } } else { Log.d(TAG,"no text detected"); } return text != null; } 

يمكنك تشغيل التطبيق والتأكد من أن النقر على النص تتم معالجته بالفعل من خلال Android Monitor Logcat .


دعونا نجعل تطبيقنا يتحدث! انتقل إلى بداية Activity وابحث عن طريقة onCreate . عند بدء التطبيق ، يجب علينا تهيئة محرك TextToSpeech للاستخدام في المستقبل.


OcrCaptureActivity.java


 @Override public void onCreate(Bundle bundle) { // (Portions of this method omitted) // TODO: Set up the Text To Speech engine. TextToSpeech.OnInitListener listener = new TextToSpeech.OnInitListener() { @Override public void onInit(final int status) { if (status == TextToSpeech.SUCCESS) { Log.d("TTS", "Text to speech engine started successfully."); tts.setLanguage(Locale.US); } else { Log.d("TTS", "Error starting the text to speech engine."); } } }; tts = new TextToSpeech(this.getApplicationContext(), listener); } 

على الرغم من حقيقة أننا قمنا بتهيئة TextToSpeech بشكل صحيح ، كقاعدة ، لا تزال بحاجة إلى معالجة الأخطاء العامة ، على سبيل المثال ، عندما لا يزال المحرك غير جاهز في المرة الأولى التي تنقر فيها على النص.


TextToSpeech يعتمد أيضًا على اللغة. يمكنك تغيير اللغة بناءً على لغة النص المعترف به. لا يتم تضمين التعرف على اللغة في Mobile Vision Text API ، ولكنه متاح من خلال Google Translate API . كلغة للتعرف على النص ، يمكنك استخدام لغة جهاز المستخدم.


رائع ، كل ما تبقى هو إضافة رمز تشغيل النص في طريقة onTap .


OcrCaptureActivity.java


 private boolean onTap(float rawX, float rawY) { // TODO: Speak the text when the user taps on screen. OcrGraphic graphic = graphicOverlay.getGraphicAtLocation(rawX, rawY); TextBlock text = null; if (graphic != null) { text = graphic.getTextBlock(); if (text != null && text.getValue() != null) { Log.d(TAG, "text data is being spoken! " + text.getValue()); // Speak the string. tts.speak(text.getValue(), TextToSpeech.QUEUE_ADD, null, "DEFAULT"); } else { Log.d(TAG, "text data is null"); } } else { Log.d(TAG,"no text detected"); } return text != null; } 

الآن ، عند بدء التطبيق والنقر على النص المكتشف ، سيقوم جهازك بتشغيله. جربها!


إتمام


الآن لديك تطبيق يمكنه التعرف على النص من الكاميرا والتحدث بصوت عال!


يمكنك تطبيق المعرفة المكتسبة من التعرف على النص في تطبيقاتك الأخرى. على سبيل المثال ، اقرأ العناوين وأرقام الهواتف من بطاقات العمل ، ابحث في النص من صور فوتوغرافية لمستندات مختلفة. باختصار ، استخدم OCR حيثما تريد التعرف على النص في الصورة.


المصدر

Source: https://habr.com/ru/post/ar412679/


All Articles