OCR – zrobię to sam…

Jak część z was zapewne wie, bawię się w czytanie różnego rodzaju obrazków, popularnie nazywanych captcha – takie niegroźne hobby (nigdzie nie publikowane, bez robienia szkód serwisom, które mają “słabe” captcha). W przypadku niektórych używałem gocr do ostatecznego odczytania tekstu (przez lenistwo) – niestety ostatnio gocr mnie zawodził, więc…

…postanowiłem napisać swój system rozpoznawania znaków. System bardzo prosty, ale jednocześnie bardzo skuteczny – opierający się na rozpoznawaniu wybranych elementów charakterystycznych dla znaków. Nie pozwala on co prawda na czytanie skanów, ale bez problemu rozpozna teksty drukowane na obrazkach.

W pierwszym etapie filtruję obrazki (usuwając wszelkie śmieci, które mogą zniekształcić obrazek), pozostałość (kiedy zostają już tylko litery)  robię cz/b, rozbijam na pojedyncze litery (zapomniałem dodać, że sprawdzam, czy litera nie jest przekręcona),  a te litery parsuję moim “OCR” (doszedłem do wniosku, że gdybym miał z miesiąc wolnego, mógłbym napisać “poważny” OCR, ale z pracy 3 dniowej też jestem zadowolony).

W pojedynczych literkach skupiam się na kilku charakterysytycznych cechach (ATM mówimy jedynie o literach drukowanych, małe literki pojawią się w wersji 2.0) – liniach prostych, skosach i zaokrągleniach – ścięciach. Okazuje się, że wcale nie jest ich tak dużo, oraz że litery różnią się znacząco od siebie. Po pierwszym filtrze zostaje nam ~2-6 liter, które trzeba dokładniej sprawdzić, po drugim zostaje max 3 (zazwyczaj 1), dla których porównujemy zapisane różnice (np. między D a O różnice są w prawym górnym i lewym dolnym rogu, różnica między F i E jest na dolnej kresce i dolnym prawym rogu – ale te różnice powinny zostać wychwycone już w pierwszych 2 etapcach i jedna z nich powinna zostać wykluczona).

System doskonale sprawdza się w przypadku liter drukowanych i “prostych” znaków – choć zapewne, jeśli sprecyzować dokładność sprawdzania (np. dla rogów mam sprawdzanie, czy jest prostokąt w pełni wypełniony, czy wypełniony “po skosie prawym (slash)”, “skosie lewym (backslash)” i która część skosu jest zapełniona.

Docelowo planuję jeszcze dodać (w przypadku, jeśli zostaną jakieś niepewności (G vs 6 – sprawdzenie, czy jest połączenie między kreseczką w środku) sposób porównywania właśnie typowych “niepewnych”.

System jeszcze nie dokończony, a już pojawił się nowy model sprawdzania litery – opływanie. Dla pojedynczej litery sprawdzamy jak wygląda jej kształt zamieniony na proste, w przypadku których koniec jednej jest początkiem drugiej (trudno to opisać, łatwo zobaczyć na rysunku, ale takowego akurat nie posiadam). Proste krótkie są później zamieniane na dłuższe (3 proste, których X zmienł się o 4px, a Y o 30 można śmiało zamienić na jedną długą z X początkowym pierwszego punktu, i końcowym ostatniego) – i te proste byłyby później porównywane. System ten, jest dużo bardziej skomplikowany, ale osiągnięty efekt może być dużo lepszy.

…a w trakcie pisania powyższego paragrafu, doszedłem do wniosku, że potrzebny mi będzie jeszcze system usuwania kapitalików przed parsowaniem liter…