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