كيفية التعرف على النص من صورة: ميزات جديدة لإطار الرؤية

الآن أصبح بإمكان إطار Vision التعرف على النص بشكل حقيقي ، وليس كما كان من قبل. نتطلع إلى متى يمكننا تطبيق هذا على Dodo IS. في هذه الأثناء ، ترجمة لمقال عن التعرف على البطاقات من لعبة اللوحة The Magic The Gathering واستخراج المعلومات النصية منها.




تم تقديم إطار Vision لأول مرة لعامة الناس في WWDC في عام 2017 ، إلى جانب iOS 11.

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

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

تم حل هذه المشكلة في تحديث Vision ، الذي تم تضمينه في iOS 13. يوفر إطار Vision الآن التعرف الحقيقي على النص.

لاختبار ذلك ، قمتُ بإنشاء تطبيق بسيط جدًا يمكنه التعرف على البطاقة من لعبة اللوحة The Magic The Gathering واستخراج معلومات نصية منها:

  • اسم البطاقة
  • كود الاصدار
  • رقم الجمع (ويعرف أيضا باسم الرمز البريدي).

فيما يلي مثال لخريطة ونص محدد أود تلقيهما.



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

نحتاج أولاً إلى إنشاء VNRecognizeTextRequest . في جوهره ، هذا وصف لما نأمل في التعرف عليه ، بالإضافة إلى إعداد لغة التعرف ومستوى الدقة:

 let request = VNRecognizeTextRequest(completionHandler: self.handleDetectedText) request.recognitionLevel = .accurate request.recognitionLanguages = ["en_GB"] 

تحتوي كتلة الإكمال على handleDetectedText(request: VNRequest?, error: Error?) . نقوم VNRecognizeTextRequest مُنشئ VNRecognizeTextRequest ثم VNRecognizeTextRequest بتعيين الخصائص المتبقية.

يتوفر مستويان من دقة الاعتراف .fast و. .accurate . نظرًا لأن بطاقتنا تحتوي على نص صغير إلى حد ما في الأسفل ، فقد اخترت دقة أعلى. ربما يكون الخيار الأسرع مناسبًا لوحدات التخزين الكبيرة للنص.

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

  • customWords : يمكنك إضافة مجموعة من السلاسل لاستخدامها في أعلى المعجم المدمج. هذا مفيد إذا كان هناك أي كلمات غير عادية في النص الخاص بك. لم أستخدم الخيار لهذا المشروع. ولكن إذا كنت سأقدم تطبيق التعرف على بطاقة Magic The Gathering التجارية ، فسأضيف بعضًا من أكثر البطاقات تعقيدًا (على سبيل المثال ، Fblthp ، The Lost ) لتجنب المشكلات.
  • minimumTextHeight : هذه هي قيمة تعويم. إنه يشير إلى الحجم بالنسبة لارتفاع الصورة التي لم يعد يجب التعرف على النص فيها. إذا قمت بإنشاء هذا الماسح الضوئي فقط للحصول على اسم الخريطة ، فسيكون من المفيد حذف جميع النصوص الأخرى غير المطلوبة. لكنني أحتاج إلى أصغر أجزاء النص ، لذلك حتى الآن لقد تجاهلت هذه الخاصية. من الواضح ، إذا تجاهلت النصوص الصغيرة ، فستكون سرعة التعرف أعلى.

الآن بعد أن وصلنا طلبنا ، يجب أن نمرره مع الصورة إلى معالج الطلب:

 let requests = [textDetectionRequest] let imageRequestHandler = VNImageRequestHandler(cgImage: cgImage, orientation: .right, options: [:]) DispatchQueue.global(qos: .userInitiated).async { do { try imageRequestHandler.perform(requests) } catch let error { print("Error: \(error)") } } 

يمكنني استخدام الصورة مباشرة من الكاميرا ، وتحويلها من UIImage إلى CGImage . يتم استخدام هذا في VNImageRequestHandler مع VNImageRequestHandler الاتجاه لمساعدة المعالج على فهم النص الذي يجب التعرف عليه.

كجزء من هذا العرض التوضيحي ، لا أستخدم الهاتف إلا في اتجاه عمودي. بطبيعة الحال ، أود أن أضيف التوجه. باداجي!

اتضح أن اتجاه الكاميرا على جهازك مفصول تمامًا عن دوران الجهاز ويُعتبر دائمًا إلى اليسار (كما كان افتراضيًا في عام 2009 ، لالتقاط الصور التي تحتاجها لإبقاء الهاتف في اتجاه أفقي). بالطبع ، تغيرت الأوقات ، وقمنا في الأساس بتصوير الصور ومقاطع الفيديو بتنسيق عمودي ، لكن الكاميرا لا تزال محاذاة إلى اليسار.

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

 func handleDetectedText(request: VNRequest?, error: Error?) { if let error = error { print("ERROR: \(error)") return } guard let results = request?.results, results.count > 0 else { print("No text found") return } for result in results { if let observation = result as? VNRecognizedTextObservation { for text in observation.topCandidates(1) { print(text.string) print(text.confidence) print(observation.boundingBox) print("\n") } } } } 

يعرض معالجنا استعلامنا ، الذي يحتوي الآن على خاصية النتائج. كل نتيجة هي VNRecognizedTextObservation ، والتي بالنسبة لنا لديها العديد من الخيارات للنتيجة (المشار إليها فيما يلي - المرشحين).

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

في هذا المثال ، نحتاج إلى النتيجة الأولى فقط ، لذلك نقوم بالحلقة من خلال observation.topCandidates(1) واستخراج النص والثقة. بينما لدى المرشح نفسه نص وثقة .boundingBox يبقى .boundingBox هو. يستخدم .boundingBox نظام إحداثيات طبيعي مع الأصل في الركن الأيسر السفلي ، لذلك إذا كان سيتم استخدامه في UIKit في المستقبل ، من أجل راحتك ، يجب تحويله.

هذا كل ما تحتاجه تقريبًا. إذا قمت بتشغيل صورة للبطاقة من خلال ذلك ، فسوف أحصل على النتيجة التالية في أقل من 0.5 ثانية على iPhone XS Max:

 Carnage Tyrant 1.0 (0.2654155572255453, 0.6955686092376709, 0.18710780143737793, 0.019915008544921786) Creature 1.0 (0.26317582130432127, 0.423814058303833, 0.09479101498921716, 0.013565015792846635) Dinosaur 1.0 (0.3883238156636556, 0.42648010253906254, 0.10021591186523438, 0.014479541778564364) Carnage Tyrant can't be countered. 1.0 (0.26538230578104655, 0.3742666244506836, 0.4300231456756592, 0.024643898010253906) Trample, hexproof 0.5 (0.2610074838002523, 0.34864263534545903, 0.23053167661031088, 0.022259855270385653) Sun Empire commanders are well versed 1.0 (0.2619712670644124, 0.31746063232421873, 0.45549616813659666, 0.022649812698364302) in advanced martial strategy. Still, the 1.0 (0.2623249689737956, 0.29798884391784664, 0.4314465204874674, 0.021180248260498136) correct maneuver is usually to deploy the 1.0 (0.2620727062225342, 0.2772137641906738, 0.4592740217844645, 0.02083740234375009) giant, implacable death lizard. 1.0 (0.2610833962758382, 0.252408218383789, 0.3502468903859457, 0.023736238479614258) 7/6 0.5 (0.6693102518717448, 0.23347826004028316, 0.04697717030843107, 0.018937730789184593) 179/279 M 1.0 (0.24829587936401368, 0.21893787384033203, 0.08339192072550453, 0.011646795272827193) XLN: EN N YEONG-HAO HAN 0.5 (0.246867307027181, 0.20903720855712893, 0.19095951716105145, 0.012227916717529319) TN & 0 2017 Wizards of the Coast 1.0 (0.5428387324015299, 0.21133480072021482, 0.19361832936604817, 0.011657810211181618) 

هذا لا يصدق! تم التعرف على كل جزء من النص ، ووضعه في المربع المحيط به ، وتم إرجاعه كنتيجة بمعدل ثقة 1.0.

حتى حقوق التأليف والنشر الصغيرة جدا في الغالب صحيحة. كل هذا تم على صورة بحجم 3024 × 4032 يزن 3.1 ميغابايت. ستكون العملية أسرع إذا قمت أولاً بتخفيض الصورة. تجدر الإشارة إلى أن هذه العملية أسرع بكثير على رقائق الكترونية A12 جديدة ، والتي لديها محرك عصبي خاص.

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

ملاحظة: في الواقع ، أحتاج فقط إلى رمز الإصدار ورقم المجموعة (إنه فهرس). ثم يمكن استخدامها في واجهة برمجة تطبيقات خدمة Scryfall للحصول على جميع المعلومات الممكنة حول هذه الخريطة ، بما في ذلك قواعد اللعبة والتكلفة.



تطبيق نموذج متاح على جيثب .

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


All Articles