Google udostępniło API pozwalające na rozpoznawanie obrazów. W liście funkcjonalności możemy znaleźć wiele ciekawych pozycji:
- Label Detection – kategoryzowanie zawartości obrazka, możemy otrzymać informację, że na obrazku znajduje się zwierzę,
- Explicit Content Detection – wykrywanie nieodpowiedniej zawartości – takiej jak przemoc czy treści dla dorosłych
- Logo Detection – wykrywa logo znanych marek,
- Landmark Detection – wykrywanie znanych budowli,
- Optical Character Recognition (OCR) – rozpoznawanie tekstu,
- Face Detection – wykrywanie twarzy na zdjęciu,
- Image Attributes – podaje informacje o obrazie, np. dominujący kolor
W tym poście pokażę jak skorzystać z rozpoznawania tekstu na przykładzie zdjęcia paragonu 🙂
Jak zawsze przykładowy kod można znaleźć na moim GitHubie w postaci gotowego do uruchomienia projektu. Kod z postu znajduje się pod adresem: https://github.com/mloza/google-cloud-storage
Chciałem jeszcze wcześniej wspomnieć o bardzo ważnej rzeczy, a mianowicie Vison API nie rozpoznaje polskich znaków, wspiera tylko alfabet łaciński. Jednak w zamian oferuje pierwsze 1,000 requestów do API za darmo.

Punktem wyjścia będzie projekt z poprzedniego postu o Google Cloud Storage, tam pokazywałem jak się uwierzytelnić i jak wysłać coś do chmury. Tym razem też musimy przesłać obrazek do Cloud Storage przed jego przetworzeniem. Jak już wspomniałem wcześniej, naszą ofiarą będzie zdjęcie paragonu:
Zdjęcie jest wyraźne, paragon lekko pomięty, ale wciąż bardzo czytelny. Nie powinno być problemu z rozpoznaniem zawartości. Zatem do dzieła.
Przesłanie obrazka do bucketu.
Autoryzacja i tworzenie obiektów API opisywałem w poprzednim poście. Kod znajduje się również w GitHubie. Dla przypomnienia kod, który tworzy klienta Google Cloud Storage, wygląda następująco:
| HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); | |
| JsonFactory jsonFactory = new JacksonFactory(); | |
| Credential credential = GoogleCredential | |
| .fromStream( | |
| Main.class.getClassLoader() | |
| .getResourceAsStream("client-secrets.json")) | |
| .createScoped(Collections.singleton(StorageScopes.CLOUD_PLATFORM)); | |
| Storage storage = new Storage.Builder(httpTransport, jsonFactory, credential) | |
| .setApplicationName("Test project") | |
| .build(); |
Pierwszym krokiem jest przesłanie zdjęcia do chmury, gdzie usługa Vision będzie mogła się do niego dostać. Odpowiada za to następujący kod:
| InputStreamContent mediaContent = new InputStreamContent("image/jpeg", | |
| getClass().getClassLoader().getResourceAsStream(PICTURE_NAME)); | |
| StorageObject object = storage | |
| .objects() | |
| .insert(BUCKET, null, mediaContent) | |
| .setName(PICTURE_NAME) | |
| .execute(); | |
| System.out.println("Adres przesÅanego obrazu: "+object.getSelfLink()); |
Mamy już obrazek w buckecie, Yay!
Rozpoznawanie tekstu
Potrzebujemy nowej zależności w pom.xml do biblioteki vision:
| <dependency> | |
| <groupId>com.google.apis</groupId> | |
| <artifactId>google-api-services-vision</artifactId> | |
| <version>v1-rev15-1.22.0</version> | |
| </dependency> |
Podobnie jak do Storage tworzymy sobie klienta Vision, który pozwoli nam na wywoływanie metod z API:
| Vision visionClient = new Vision.Builder(httpTransport, jsonFactory, credential) | |
| .setApplicationName(APPLICATION_NAME) | |
| .build(); |
Mając klienta, możemy przejść do wywołania żądania przetworzenia obrazu. Jest ono dość duże w porównaniu z poprzednimi przykładami kodu:
| Image image = new Image().setSource(new ImageSource() //1 | |
| .setGcsImageUri("gs://" + BUCKET + "/" + PICTURE_NAME)); | |
| Feature annotateFeature = new Feature() //2 | |
| .setType("TEXT_DETECTION"); | |
| AnnotateImageRequest annotateImage = new AnnotateImageRequest() // 3 | |
| .setFeatures(Collections.singletonList(annotateFeature)) | |
| .setImage(image); | |
| BatchAnnotateImagesResponse text_detection = visionClient // 4 | |
| .images() | |
| .annotate( | |
| new BatchAnnotateImagesRequest() | |
| .setRequests(Collections.singletonList(annotateImage))) | |
| .execute(); | |
| System.out.println(text_detection.getResponses().get(0).getTextAnnotations()); //5 |
Najpierw tworzymy obiekt reprezentujący nasz obrazek, podając url w postaci gs://nazwa-bucketu/nazwa-obrazka.jpg [1]. Następnie tworzymy obiekt, który będzie reprezentował, co chcemy otrzymać z obrazka, w naszym przypadku będzie to rozpoznawanie tekstu [2]. Kolejnym krokiem jest stworzenie obiektu zapytania, przekazując mu wcześniej stworzony obrazek oraz wymagany tryb przetwarzania [3]. Ostatnim krokiem jest wysłanie zapytania z użyciem wcześniej stworzonego klienta [4]. W jednym zapytaniu możemy przekazać większą ilość obrazków do przetworzenia, jeśli zajdzie taka potrzeba.
W odpowiedzi dostaniemy JSON, który zawiera pełny tekst z obrazka oraz poszczególne słowa/fragmenty wraz z koordynatami, w którym miejscu został rozpoznany. Odpowiedź z serwisu dotycząca naszego testowego zdjęcia paragonu wygląda następująco (uwaga, 1429 linii po sformatowaniu!):
| [ | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 337, | |
| "y": 801 | |
| }, | |
| { | |
| "x": 2242, | |
| "y": 801 | |
| }, | |
| { | |
| "x": 2242, | |
| "y": 2787 | |
| }, | |
| { | |
| "x": 337, | |
| "y": 2787 | |
| } | |
| ] | |
| }, | |
| "description": "SKLEP \"ZABKA'' Z3816\nul. Mogilska 59, 31-545 Krakow\nPHU \"DANA\"\nNIP 678-185-16-34\n2016-05-29\nnr Wydr 808669\nPARAGON FISKALNY\nMLEKO KONECKIE D\n2,50 zh. 2,50 D\nMLEKO KONECKIE D 1 2,50 zt, 2,50 D\nSprzed. opod. PTU D\n5,00\nKwota D 05,00%\n0,24\nPodatek PTU\n0,24\nSUMA PLN\n5,00\n0003241 5 MACIEK\n08:43\n1EIOS-NLNTD-0GXTD-ON09 G-XYUSE\nBAE 13112254\nPtatno\na kred\n5,00\n501782\n", | |
| "locale": "pl" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 876, | |
| "y": 801 | |
| }, | |
| { | |
| "x": 1089, | |
| "y": 801 | |
| }, | |
| { | |
| "x": 1089, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 876, | |
| "y": 898 | |
| } | |
| ] | |
| }, | |
| "description": "SKLEP" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1133, | |
| "y": 801 | |
| }, | |
| { | |
| "x": 1432, | |
| "y": 801 | |
| }, | |
| { | |
| "x": 1432, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 1133, | |
| "y": 898 | |
| } | |
| ] | |
| }, | |
| "description": "\"ZABKA''" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1475, | |
| "y": 801 | |
| }, | |
| { | |
| "x": 1693, | |
| "y": 801 | |
| }, | |
| { | |
| "x": 1693, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 1475, | |
| "y": 898 | |
| } | |
| ] | |
| }, | |
| "description": "Z3816" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 662, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 778, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 778, | |
| "y": 1009 | |
| }, | |
| { | |
| "x": 662, | |
| "y": 1009 | |
| } | |
| ] | |
| }, | |
| "description": "ul." | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 825, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 1167, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 1167, | |
| "y": 1009 | |
| }, | |
| { | |
| "x": 825, | |
| "y": 1009 | |
| } | |
| ] | |
| }, | |
| "description": "Mogilska" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1212, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 1337, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 1337, | |
| "y": 1009 | |
| }, | |
| { | |
| "x": 1212, | |
| "y": 1009 | |
| } | |
| ] | |
| }, | |
| "description": "59," | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1386, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 1648, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 1648, | |
| "y": 1009 | |
| }, | |
| { | |
| "x": 1386, | |
| "y": 1009 | |
| } | |
| ] | |
| }, | |
| "description": "31-545" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1692, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 1959, | |
| "y": 898 | |
| }, | |
| { | |
| "x": 1959, | |
| "y": 1009 | |
| }, | |
| { | |
| "x": 1692, | |
| "y": 1009 | |
| } | |
| ] | |
| }, | |
| "description": "Krakow" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1086, | |
| "y": 1010 | |
| }, | |
| { | |
| "x": 1214, | |
| "y": 1013 | |
| }, | |
| { | |
| "x": 1211, | |
| "y": 1107 | |
| }, | |
| { | |
| "x": 1083, | |
| "y": 1104 | |
| } | |
| ] | |
| }, | |
| "description": "PHU" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1259, | |
| "y": 1013 | |
| }, | |
| { | |
| "x": 1512, | |
| "y": 1020 | |
| }, | |
| { | |
| "x": 1509, | |
| "y": 1114 | |
| }, | |
| { | |
| "x": 1256, | |
| "y": 1107 | |
| } | |
| ] | |
| }, | |
| "description": "\"DANA\"" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 914, | |
| "y": 1101 | |
| }, | |
| { | |
| "x": 1037, | |
| "y": 1106 | |
| }, | |
| { | |
| "x": 1033, | |
| "y": 1206 | |
| }, | |
| { | |
| "x": 910, | |
| "y": 1201 | |
| } | |
| ] | |
| }, | |
| "description": "NIP" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1082, | |
| "y": 1107 | |
| }, | |
| { | |
| "x": 1644, | |
| "y": 1132 | |
| }, | |
| { | |
| "x": 1640, | |
| "y": 1231 | |
| }, | |
| { | |
| "x": 1078, | |
| "y": 1207 | |
| } | |
| ] | |
| }, | |
| "description": "678-185-16-34" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 390, | |
| "y": 1208 | |
| }, | |
| { | |
| "x": 824, | |
| "y": 1227 | |
| }, | |
| { | |
| "x": 820, | |
| "y": 1313 | |
| }, | |
| { | |
| "x": 386, | |
| "y": 1294 | |
| } | |
| ] | |
| }, | |
| "description": "2016-05-29" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1592, | |
| "y": 1236 | |
| }, | |
| { | |
| "x": 1680, | |
| "y": 1232 | |
| }, | |
| { | |
| "x": 1684, | |
| "y": 1332 | |
| }, | |
| { | |
| "x": 1596, | |
| "y": 1336 | |
| } | |
| ] | |
| }, | |
| "description": "nr" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1722, | |
| "y": 1231 | |
| }, | |
| { | |
| "x": 1907, | |
| "y": 1223 | |
| }, | |
| { | |
| "x": 1911, | |
| "y": 1323 | |
| }, | |
| { | |
| "x": 1726, | |
| "y": 1331 | |
| } | |
| ] | |
| }, | |
| "description": "Wydr" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1949, | |
| "y": 1220 | |
| }, | |
| { | |
| "x": 2236, | |
| "y": 1207 | |
| }, | |
| { | |
| "x": 2240, | |
| "y": 1307 | |
| }, | |
| { | |
| "x": 1953, | |
| "y": 1320 | |
| } | |
| ] | |
| }, | |
| "description": "808669" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 935, | |
| "y": 1321 | |
| }, | |
| { | |
| "x": 1254, | |
| "y": 1328 | |
| }, | |
| { | |
| "x": 1252, | |
| "y": 1433 | |
| }, | |
| { | |
| "x": 933, | |
| "y": 1426 | |
| } | |
| ] | |
| }, | |
| "description": "PARAGON" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1294, | |
| "y": 1329 | |
| }, | |
| { | |
| "x": 1638, | |
| "y": 1336 | |
| }, | |
| { | |
| "x": 1636, | |
| "y": 1441 | |
| }, | |
| { | |
| "x": 1292, | |
| "y": 1434 | |
| } | |
| ] | |
| }, | |
| "description": "FISKALNY" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 379, | |
| "y": 1421 | |
| }, | |
| { | |
| "x": 602, | |
| "y": 1421 | |
| }, | |
| { | |
| "x": 602, | |
| "y": 1515 | |
| }, | |
| { | |
| "x": 379, | |
| "y": 1515 | |
| } | |
| ] | |
| }, | |
| "description": "MLEKO" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 642, | |
| "y": 1413 | |
| }, | |
| { | |
| "x": 983, | |
| "y": 1417 | |
| }, | |
| { | |
| "x": 981, | |
| "y": 1541 | |
| }, | |
| { | |
| "x": 640, | |
| "y": 1537 | |
| } | |
| ] | |
| }, | |
| "description": "KONECKIE" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1029, | |
| "y": 1421 | |
| }, | |
| { | |
| "x": 1072, | |
| "y": 1421 | |
| }, | |
| { | |
| "x": 1072, | |
| "y": 1515 | |
| }, | |
| { | |
| "x": 1029, | |
| "y": 1515 | |
| } | |
| ] | |
| }, | |
| "description": "D" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1547, | |
| "y": 1443 | |
| }, | |
| { | |
| "x": 1720, | |
| "y": 1443 | |
| }, | |
| { | |
| "x": 1720, | |
| "y": 1525 | |
| }, | |
| { | |
| "x": 1547, | |
| "y": 1525 | |
| } | |
| ] | |
| }, | |
| "description": "2,50" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1765, | |
| "y": 1427 | |
| }, | |
| { | |
| "x": 1899, | |
| "y": 1429 | |
| }, | |
| { | |
| "x": 1897, | |
| "y": 1553 | |
| }, | |
| { | |
| "x": 1763, | |
| "y": 1551 | |
| } | |
| ] | |
| }, | |
| "description": "zh." | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1944, | |
| "y": 1443 | |
| }, | |
| { | |
| "x": 2140, | |
| "y": 1443 | |
| }, | |
| { | |
| "x": 2140, | |
| "y": 1525 | |
| }, | |
| { | |
| "x": 1944, | |
| "y": 1525 | |
| } | |
| ] | |
| }, | |
| "description": "2,50" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 2186, | |
| "y": 1443 | |
| }, | |
| { | |
| "x": 2233, | |
| "y": 1443 | |
| }, | |
| { | |
| "x": 2233, | |
| "y": 1525 | |
| }, | |
| { | |
| "x": 2186, | |
| "y": 1525 | |
| } | |
| ] | |
| }, | |
| "description": "D" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 377, | |
| "y": 1533 | |
| }, | |
| { | |
| "x": 588, | |
| "y": 1533 | |
| }, | |
| { | |
| "x": 588, | |
| "y": 1622 | |
| }, | |
| { | |
| "x": 377, | |
| "y": 1622 | |
| } | |
| ] | |
| }, | |
| "description": "MLEKO" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 640, | |
| "y": 1523 | |
| }, | |
| { | |
| "x": 981, | |
| "y": 1527 | |
| }, | |
| { | |
| "x": 980, | |
| "y": 1643 | |
| }, | |
| { | |
| "x": 639, | |
| "y": 1639 | |
| } | |
| ] | |
| }, | |
| "description": "KONECKIE" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1024, | |
| "y": 1526 | |
| }, | |
| { | |
| "x": 1101, | |
| "y": 1527 | |
| }, | |
| { | |
| "x": 1100, | |
| "y": 1643 | |
| }, | |
| { | |
| "x": 1023, | |
| "y": 1642 | |
| } | |
| ] | |
| }, | |
| "description": "D" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1255, | |
| "y": 1529 | |
| }, | |
| { | |
| "x": 1332, | |
| "y": 1530 | |
| }, | |
| { | |
| "x": 1331, | |
| "y": 1646 | |
| }, | |
| { | |
| "x": 1254, | |
| "y": 1645 | |
| } | |
| ] | |
| }, | |
| "description": "1" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1547, | |
| "y": 1553 | |
| }, | |
| { | |
| "x": 1719, | |
| "y": 1553 | |
| }, | |
| { | |
| "x": 1719, | |
| "y": 1639 | |
| }, | |
| { | |
| "x": 1547, | |
| "y": 1639 | |
| } | |
| ] | |
| }, | |
| "description": "2,50" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1762, | |
| "y": 1553 | |
| }, | |
| { | |
| "x": 1894, | |
| "y": 1553 | |
| }, | |
| { | |
| "x": 1894, | |
| "y": 1639 | |
| }, | |
| { | |
| "x": 1762, | |
| "y": 1639 | |
| } | |
| ] | |
| }, | |
| "description": "zt," | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1944, | |
| "y": 1553 | |
| }, | |
| { | |
| "x": 2141, | |
| "y": 1553 | |
| }, | |
| { | |
| "x": 2141, | |
| "y": 1639 | |
| }, | |
| { | |
| "x": 1944, | |
| "y": 1639 | |
| } | |
| ] | |
| }, | |
| "description": "2,50" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 2186, | |
| "y": 1553 | |
| }, | |
| { | |
| "x": 2232, | |
| "y": 1553 | |
| }, | |
| { | |
| "x": 2232, | |
| "y": 1639 | |
| }, | |
| { | |
| "x": 2186, | |
| "y": 1639 | |
| } | |
| ] | |
| }, | |
| "description": "D" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 371, | |
| "y": 1743 | |
| }, | |
| { | |
| "x": 675, | |
| "y": 1743 | |
| }, | |
| { | |
| "x": 675, | |
| "y": 1841 | |
| }, | |
| { | |
| "x": 371, | |
| "y": 1841 | |
| } | |
| ] | |
| }, | |
| "description": "Sprzed." | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 718, | |
| "y": 1743 | |
| }, | |
| { | |
| "x": 926, | |
| "y": 1743 | |
| }, | |
| { | |
| "x": 926, | |
| "y": 1841 | |
| }, | |
| { | |
| "x": 718, | |
| "y": 1841 | |
| } | |
| ] | |
| }, | |
| "description": "opod." | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 973, | |
| "y": 1743 | |
| }, | |
| { | |
| "x": 1110, | |
| "y": 1743 | |
| }, | |
| { | |
| "x": 1110, | |
| "y": 1841 | |
| }, | |
| { | |
| "x": 973, | |
| "y": 1841 | |
| } | |
| ] | |
| }, | |
| "description": "PTU" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1152, | |
| "y": 1743 | |
| }, | |
| { | |
| "x": 1196, | |
| "y": 1743 | |
| }, | |
| { | |
| "x": 1196, | |
| "y": 1841 | |
| }, | |
| { | |
| "x": 1152, | |
| "y": 1841 | |
| } | |
| ] | |
| }, | |
| "description": "D" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1931, | |
| "y": 1778 | |
| }, | |
| { | |
| "x": 2129, | |
| "y": 1761 | |
| }, | |
| { | |
| "x": 2138, | |
| "y": 1862 | |
| }, | |
| { | |
| "x": 1940, | |
| "y": 1880 | |
| } | |
| ] | |
| }, | |
| "description": "5,00" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 363, | |
| "y": 1850 | |
| }, | |
| { | |
| "x": 581, | |
| "y": 1850 | |
| }, | |
| { | |
| "x": 581, | |
| "y": 1950 | |
| }, | |
| { | |
| "x": 363, | |
| "y": 1950 | |
| } | |
| ] | |
| }, | |
| "description": "Kwota" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 623, | |
| "y": 1850 | |
| }, | |
| { | |
| "x": 670, | |
| "y": 1850 | |
| }, | |
| { | |
| "x": 670, | |
| "y": 1950 | |
| }, | |
| { | |
| "x": 623, | |
| "y": 1950 | |
| } | |
| ] | |
| }, | |
| "description": "D" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 715, | |
| "y": 1850 | |
| }, | |
| { | |
| "x": 979, | |
| "y": 1850 | |
| }, | |
| { | |
| "x": 979, | |
| "y": 1950 | |
| }, | |
| { | |
| "x": 715, | |
| "y": 1950 | |
| } | |
| ] | |
| }, | |
| "description": "05,00%" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1941, | |
| "y": 1888 | |
| }, | |
| { | |
| "x": 2125, | |
| "y": 1872 | |
| }, | |
| { | |
| "x": 2134, | |
| "y": 1975 | |
| }, | |
| { | |
| "x": 1950, | |
| "y": 1992 | |
| } | |
| ] | |
| }, | |
| "description": "0,24" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 356, | |
| "y": 1958 | |
| }, | |
| { | |
| "x": 663, | |
| "y": 1958 | |
| }, | |
| { | |
| "x": 663, | |
| "y": 2048 | |
| }, | |
| { | |
| "x": 356, | |
| "y": 2048 | |
| } | |
| ] | |
| }, | |
| "description": "Podatek" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 712, | |
| "y": 1958 | |
| }, | |
| { | |
| "x": 845, | |
| "y": 1958 | |
| }, | |
| { | |
| "x": 845, | |
| "y": 2048 | |
| }, | |
| { | |
| "x": 712, | |
| "y": 2048 | |
| } | |
| ] | |
| }, | |
| "description": "PTU" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1941, | |
| "y": 2000 | |
| }, | |
| { | |
| "x": 2120, | |
| "y": 1992 | |
| }, | |
| { | |
| "x": 2124, | |
| "y": 2089 | |
| }, | |
| { | |
| "x": 1945, | |
| "y": 2097 | |
| } | |
| ] | |
| }, | |
| "description": "0,24" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 352, | |
| "y": 2070 | |
| }, | |
| { | |
| "x": 704, | |
| "y": 2070 | |
| }, | |
| { | |
| "x": 704, | |
| "y": 2240 | |
| }, | |
| { | |
| "x": 352, | |
| "y": 2240 | |
| } | |
| ] | |
| }, | |
| "description": "SUMA" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 790, | |
| "y": 2070 | |
| }, | |
| { | |
| "x": 1049, | |
| "y": 2070 | |
| }, | |
| { | |
| "x": 1049, | |
| "y": 2240 | |
| }, | |
| { | |
| "x": 790, | |
| "y": 2240 | |
| } | |
| ] | |
| }, | |
| "description": "PLN" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1837, | |
| "y": 2113 | |
| }, | |
| { | |
| "x": 2196, | |
| "y": 2082 | |
| }, | |
| { | |
| "x": 2212, | |
| "y": 2268 | |
| }, | |
| { | |
| "x": 1853, | |
| "y": 2299 | |
| } | |
| ] | |
| }, | |
| "description": "5,00" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 349, | |
| "y": 2243 | |
| }, | |
| { | |
| "x": 656, | |
| "y": 2243 | |
| }, | |
| { | |
| "x": 656, | |
| "y": 2341 | |
| }, | |
| { | |
| "x": 349, | |
| "y": 2341 | |
| } | |
| ] | |
| }, | |
| "description": "0003241" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 725, | |
| "y": 2243 | |
| }, | |
| { | |
| "x": 795, | |
| "y": 2243 | |
| }, | |
| { | |
| "x": 795, | |
| "y": 2341 | |
| }, | |
| { | |
| "x": 725, | |
| "y": 2341 | |
| } | |
| ] | |
| }, | |
| "description": "5" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 838, | |
| "y": 2243 | |
| }, | |
| { | |
| "x": 1099, | |
| "y": 2243 | |
| }, | |
| { | |
| "x": 1099, | |
| "y": 2341 | |
| }, | |
| { | |
| "x": 838, | |
| "y": 2341 | |
| } | |
| ] | |
| }, | |
| "description": "MACIEK" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1984, | |
| "y": 2282 | |
| }, | |
| { | |
| "x": 2200, | |
| "y": 2282 | |
| }, | |
| { | |
| "x": 2200, | |
| "y": 2361 | |
| }, | |
| { | |
| "x": 1984, | |
| "y": 2361 | |
| } | |
| ] | |
| }, | |
| "description": "08:43" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 616, | |
| "y": 2342 | |
| }, | |
| { | |
| "x": 1576, | |
| "y": 2362 | |
| }, | |
| { | |
| "x": 1574, | |
| "y": 2467 | |
| }, | |
| { | |
| "x": 614, | |
| "y": 2447 | |
| } | |
| ] | |
| }, | |
| "description": "1EIOS-NLNTD-0GXTD-ON09" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1598, | |
| "y": 2363 | |
| }, | |
| { | |
| "x": 1887, | |
| "y": 2369 | |
| }, | |
| { | |
| "x": 1885, | |
| "y": 2474 | |
| }, | |
| { | |
| "x": 1596, | |
| "y": 2468 | |
| } | |
| ] | |
| }, | |
| "description": "G-XYUSE" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1109, | |
| "y": 2471 | |
| }, | |
| { | |
| "x": 1242, | |
| "y": 2471 | |
| }, | |
| { | |
| "x": 1242, | |
| "y": 2572 | |
| }, | |
| { | |
| "x": 1109, | |
| "y": 2572 | |
| } | |
| ] | |
| }, | |
| "description": "BAE" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1290, | |
| "y": 2463 | |
| }, | |
| { | |
| "x": 1642, | |
| "y": 2478 | |
| }, | |
| { | |
| "x": 1637, | |
| "y": 2582 | |
| }, | |
| { | |
| "x": 1285, | |
| "y": 2567 | |
| } | |
| ] | |
| }, | |
| "description": "13112254" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 337, | |
| "y": 2580 | |
| }, | |
| { | |
| "x": 603, | |
| "y": 2568 | |
| }, | |
| { | |
| "x": 606, | |
| "y": 2653 | |
| }, | |
| { | |
| "x": 341, | |
| "y": 2665 | |
| } | |
| ] | |
| }, | |
| "description": "Ptatno" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1310, | |
| "y": 2578 | |
| }, | |
| { | |
| "x": 1353, | |
| "y": 2580 | |
| }, | |
| { | |
| "x": 1348, | |
| "y": 2673 | |
| }, | |
| { | |
| "x": 1305, | |
| "y": 2671 | |
| } | |
| ] | |
| }, | |
| "description": "a" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1402, | |
| "y": 2586 | |
| }, | |
| { | |
| "x": 1578, | |
| "y": 2586 | |
| }, | |
| { | |
| "x": 1578, | |
| "y": 2680 | |
| }, | |
| { | |
| "x": 1402, | |
| "y": 2680 | |
| } | |
| ] | |
| }, | |
| "description": "kred" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 2011, | |
| "y": 2593 | |
| }, | |
| { | |
| "x": 2188, | |
| "y": 2587 | |
| }, | |
| { | |
| "x": 2191, | |
| "y": 2680 | |
| }, | |
| { | |
| "x": 2014, | |
| "y": 2686 | |
| } | |
| ] | |
| }, | |
| "description": "5,00" | |
| }, | |
| { | |
| "boundingPoly": { | |
| "vertices": [ | |
| { | |
| "x": 1923, | |
| "y": 2696 | |
| }, | |
| { | |
| "x": 2184, | |
| "y": 2693 | |
| }, | |
| { | |
| "x": 2185, | |
| "y": 2782 | |
| }, | |
| { | |
| "x": 1924, | |
| "y": 2785 | |
| } | |
| ] | |
| }, | |
| "description": "501782" | |
| } | |
| ] | |
|  |
Cały rozpoznany tekst w porównaniu z obrazkiem:
SKLEP "ZABKA'' Z3816 ul. Mogilska 59, 31-545 Krakow PHU "DANA" NIP 678-185-16-34 2016-05-29 nr Wydr 808669 PARAGON FISKALNY MLEKO KONECKIE D 2,50 zh. 2,50 D MLEKO KONECKIE D 1 2,50 zt, 2,50 D Sprzed. opod. PTU D 5,00 Kwota D 05,00% 0,24 Podatek PTU 0,24 SUMA PLN 5,00 0003241 5 MACIEK 08:43 1EIOS-NLNTD-0GXTD-ON09 G-XYUSE BAE 13112254 Ptatno a kred 5,00 501782

Jak widać, program poradził sobie całkiem dobrze z tym zadaniem, trochę trudności mu sprawiły polskie litery. Sprawdzałem jego działanie również z większym paragonem, gdzie literki już nie były tak wyraźne i wyniki były równie zadowalające, nie było już tak poprawnie jak w przykładzie, jednak wciąż większość była rozpoznana poprawnie. Przy cenach proponowanych przez Google wygląda to bardzo dobrze. Zastanawiam się tylko czy z powodu opublikowania API zmienili mechanizm reCaptchy z przepisywania słów na klikanie w obrazki :]

Szukałem w grafice Google mleka Koneckiego i wyświetlił mi się ten paragon