iOS – Offline’owe rozpoznawanie tekstu (OCR) i tłumaczenie z wykorzystaniem ML Kit, Apple Vision i Tesseract

W tym artykule przedstawię techniczne szczegóły implementacji demonstracyjnej aplikacji iOS, zaprojektowanej w celu zaprezentowania możliwości offline’owego rozpoznawania tekstu (OCR) w czasie rzeczywistym, tłumaczenia tekstu oraz skanowania kodów kreskowych.

Pełny kod źródłowy jest dostępny w repozytorium GitHub: https://github.com/AndreiMaksimovich/ios-live-offline-ocr-and-translation–demo

Stack technologiczny

Aplikacja została napisana w języku Swift z wykorzystaniem SwiftUI jako frameworka interfejsu użytkownika.

OCR

Aplikacja integruje kilka bibliotek, aby zapewnić działanie offline’owego OCR w czasie rzeczywistym:

ML Kit

API Google ML Kit Text Recognition v2 (działające lokalnie/offline) obsługuje rozpoznawanie tekstu w językach wykorzystujących znaki chińskie, dewanagari (północno-indyjski), japońskie, koreańskie oraz alfabet łaciński.

Dowiedz się więcej: https://developers.google.com/ml-kit/vision/text-recognition/v2

Apple Vision

Framework Apple Vision obsługuje rozpoznawanie tekstu na urządzeniu w 18 językach, w tym:
angielski (USA, Wielka Brytania, Australia), francuski (Francja, Kanada), niemiecki, włoski, hiszpański (Hiszpania, Meksyk), portugalski (Brazylia), chiński (uproszczony — zh-Hans, tradycyjny — zh-Hant, Hongkong), japoński, koreański, arabski, rosyjski oraz ukraiński.

Dowiedz się więcej: https://developer.apple.com/documentation/vision/recognizing-text-in-images

Tesseract

Tesseract to otwartoźródłowy silnik OCR udostępniony na licencji Apache 2.0, zdolny do rozpoznawania tekstu w szerokim zakresie języków (lista języków).
W tym projekcie użyto biblioteki Tesseract-OCR-iOS, opartej na Tesseract v3 (naj­nowsza dostępna wersja w chwili pisania to v5.5.1).
Jest to starsza implementacja wykorzystująca CPU do przetwarzania, co czyni ją wolniejszą w porównaniu z Google ML Kit oraz Apple Vision.
W tym demo jej głównym zadaniem jest pełnienie roli mechanizmu zapasowego dla rzadziej spotykanych języków, np. gruzińskiego (Khartuli).

Dowiedz się więcej:

Offline’owe tłumaczenie na urządzeniu

Do tłumaczenia offline projekt wykorzystuje Google ML Kit Translation, który obsługuje ponad 50 języków:
https://developers.google.com/ml-kit/language/translation/translation-language-support.
Modele tłumaczeń są pobierane na żądanie, a choć jakość tłumaczenia nie jest idealna, jest wystarczająca do praktycznych zastosowań, takich jak tłumaczenie etykiet, znaków i krótkich fragmentów tekstu.

Dowiedz się więcej:
https://developers.google.com/ml-kit/language/translation

Skaner kodów kreskowych

Do skanowania kodów kreskowych aplikacja wykorzystuje ML Kit Barcode Scanner API, który obsługuje szeroki zakres popularnych formatów:

  • Liniowe: Codabar, Code 39, Code 93, Code 128, EAN-8, EAN-13, ITF, UPC-A, UPC-E
  • 2D: Aztec, Data Matrix, PDF417, QR Code

Dowiedz się więcej:
https://developers.google.com/ml-kit/vision/barcode-scanning

Architektura aplikacji

Aplikacja została zbudowana w oparciu o SwiftUI, a jej architektura w zakresie zarządzania stanem oraz udostępniania usług i API opiera się na kontekstowym użyciu komponentów, z pełnym wsparciem dla SwiftUI Previews oraz wydajnych testów na urządzeniu i poza nim.

Stan aplikacji

Aplikacja jest na tyle prosta, że korzysta z jednego globalnego obiektu @Observable (AppState) do zarządzania stanem globalnym.
Dla poszczególnych widoków wykorzystywane są ViewModel-e, które zarządzają stanem lokalnym. W niektórych przypadkach wartości modelu są przekazywane bezpośrednio do widoków podrzędnych — ponieważ w tym projekcie nie ma potrzeby stosowania złożonych modeli współdzielonych lub kontekstowych.

Usługi i API

Aplikacja korzysta z jednego centralnego punktu dostępu do wszystkich usług i interfejsów API — globalnego obiektu @Observable (AppCore).
Wszystkie serwisy, fabryki i API są zaprojektowane jako komponenty abstrakcyjne, co umożliwia ich rekonfigurację podczas inicjalizacji aplikacji, testów lub debugowania — np. w celu użycia wersji produkcyjnych, mocków, proxy lub danych testowych.

Współbieżność

Aplikacja wykorzystuje DispatchQueue, aby zapewnić uporządkowane wykonywanie zadań w tle związanych z kamerą.
Podsystem kamery stosuje również mechanizm blokady właściciela (Owner Lock), aby zapobiec nakładaniu się lub nadmiernemu uruchamianiu operacji konfiguracyjnych.
Wszystkie usługi i API działają asynchronicznie na głównym wątku, natomiast czasochłonne zadania są delegowane do wątków roboczych przy użyciu dedykowanych kolejek, co zapewnia responsywność i stabilność działania.

Kamera

System kamery opiera się na architekturze Provider–Client, w której kamera jest automatycznie inicjalizowana lub zatrzymywana w zależności od dostępności aktywnych klientów.
Komponenty takie jak Camera Preview View oraz usługi przechwytywania obrazu/wideo działają jako klienci kamery, współdzieląc dostęp do wspólnego dostawcy i efektywnie zarządzając zasobami.

OCR

System OCR został zaimplementowany jako warstwa abstrakcji / zunifikowany interfejs API, integrujący Tesseract, ML Kit oraz Apple Vision w ramach wspólnego interfejsu.
Wykorzystuje standaryzowane struktury wyników OCR oraz prostą asynchroniczną API do dostarczania funkcjonalności rozpoznawania tekstu.
Metadane językowe wbudowane w aplikację definiują preferowany silnik OCR oraz jego konfigurację, co umożliwia elastyczną inicjalizację według schematu:
Język docelowy → Informacje o modelu i konfiguracja → Fabryka usług OCR → Zainicjalizowana instancja OCR Service.

Tłumaczenie na żywo

System tłumaczeń na żywo został zbudowany w oparciu o ten sam wzorzec architektoniczny co OCR.
Proces inicjalizacji przebiega według schematu:
Języki źródłowy i docelowy → Mapowanie języków ML Kit → Fabryka usług tłumaczenia → Zainicjalizowana instancja Translation Service.

Skaner kodów kreskowych

Skaner kodów kreskowych to najprostszy komponent w systemie — nie wykorzystuje fabryk ani zunifikowanych struktur wynikowych.
Zamiast tego oferuje prostą abstrakcję API, która bezpośrednio zwraca wyniki z ML Kit Barcode Scanner.

Cykl OCR

Cykl działania systemu OCR w aplikacji przebiega w sposób prosty i asynchroniczny:

  1. Przechwycenie klatki wideo za pomocą usługi kamery.
  2. Rozpoznanie tekstu (OCR) na podstawie bieżącego modelu.
  3. Tłumaczenie wyników OCR (jeśli aktywne).
  4. Skanowanie kodów kreskowych w tej samej klatce.
  5. Publikacja wyników do wspólnego modelu.
  6. Krótka przerwa i powtórzenie cyklu.

Interfejs użytkownika

Widok inicjalizacyjny

Aplikacja uruchamia się od widoku inicjalizacyjnego, który pełni typową dla wersji demonstracyjnych rolę wstępnej inicjalizacji danych.
W tym przypadku służy on do sprawdzenia uprawnień do korzystania z kamery oraz pobrania modeli tłumaczeń przed uruchomieniem głównej części aplikacji.
W produkcyjnej wersji aplikacji ten etap powinien zostać zastąpiony mechanizmem inicjalizacji zasobów na żądanie.

Widok główny

Główny widok aplikacji pełni rolę niestandardowego widoku kart (tab view), zaprojektowanego w taki sposób, aby zapewnić pełną kontrolę nad cyklem życia każdego widoku.
W obecnej implementacji każda karta zawiera pojedynczy widok, jednak system można w łatwy sposób rozbudować o:

  • oddzielną nawigację dla każdej karty,
  • historię nawigacji,
  • funkcje takie jak podwójne stuknięcie w ikonę karty, aby zresetować jej stos historii.

Podgląd kamery

Widok podglądu kamery (Camera Preview View) jest warstwą SwiftUI, opakowującą widok oparty na UIKit (CameraPreviewLayerView).
Jego model działa jako klient kamery, zarządzający połączeniem oraz interakcją z globalnym menedżerem kamery.

Widok wyników

Widok wyników (Result View) jest nakładką na podgląd kamery.
Otrzymuje on wyniki OCR, wyniki skanowania kodów kreskowych oraz meta dane obrazu źródłowego bezpośrednio z nadrzędnego modelu widoku.
Na podstawie tych danych renderuje tekst i prostokąty obramowujące wykryte elementy, korzystając z komponentu Canvas dostępnego w SwiftUI.

Co dalej

Tesseract

Aktualnie używany wrapper Tesseract opiera się na starszej wersji silnika.
Aktualizacja do Tesseract v5 byłaby znaczącym ulepszeniem, ponieważ nowa wersja wprowadza eksperymentalne wsparcie dla OpenCL, które może znacznie skrócić czas przetwarzania, przenosząc obliczenia na GPU.

AR

Zastąpienie podglądu kamery widokiem AR View mogłoby znacząco poprawić doświadczenie użytkownika.
Rozpoznane fragmenty tekstu mogłyby pełnić rolę punktów zakotwiczenia AR (AR Anchors), na których wyświetlane byłyby trójwymiarowe nakładki tekstowe poruszające się wraz z obiektami, co zapewniłoby bardziej interaktywny i atrakcyjny wizualnie interfejs.

Analiza obrazu

Analiza obrazu może być wykorzystana jako etap wstępnego przetwarzania przed uruchomieniem OCR.
Przykładowo, dzięki AR system może koncentrować się na rozpoznawaniu tekstu na wykrytych powierzchniach, wykorzystując ich pozycję do korekty perspektywy i ustawienia tekstu w prawidłowej orientacji frontowej.
Na urządzeniach z LiDAR-em dane głębi mogą dodatkowo pomóc w rozróżnianiu obiektów.
Z kolei Apple Vision oraz Google ML Kit mogą pomóc w podziale obrazu na mniejsze, kontekstowe fragmenty, co zwiększa dokładność i wydajność OCR.

Buforowanie / pamięć wyników

Dzięki integracji z AR Anchoring warto wprowadzić system buforowania wyników (Result Caching / Memory).
Pozwoli on na stopniową aktualizację rozpoznanych fragmentów z większą dokładnością, a także na eksperymentowanie z efektami i filtrami w obszarach o niskiej pewności rozpoznania, pomijając te o wysokim poziomie pewności.

Filtry i efekty obrazu

OCR osiąga najlepsze wyniki na obrazach o wysokim kontraście, najlepiej w skali szarości lub w czerni i bieli.
Aby poprawić skuteczność w trudniejszych warunkach, warto zintegrować efekty transformacyjne i filtry obrazu bezpośrednio z procesem OCR.
Można również wytrenować własną sieć neuronową, która automatycznie rozpoznawałaby problematyczne obszary i dobierała odpowiednie filtry — np. w przypadku czerwonego tekstu na czarnym tle.