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…


2008-06-17 15:30
Nieźle, myślałem że technika OCR to coś bardzo skomplikowanego. W życiu nie pomyślałbym, że jakieś proste OCR dla zabawy można napisać w 3 dni.
2008-06-18 10:01
Wszystko opiera się na prostych zasadach, które każdy może wymyśleć - nie gwarantują one co prawda rozpoznawania tekstu w sytuacjach ekstremalnych (złe skany) - ale do moich potrzeb są wystarczające.
Co więcej - ATM mam rozpoznawanie wyłącznie pojedynczych liter (ze względu na captcha, jest to rozwiązanie, do którego dążyłem) - mając do dyspozycji “kartkę liter”, można wiązać pewnego rodzaju dopasowania (albo, jak to jest w “poważnych programach OCR” - dawać użytkownikowi możliwość poprawy błędnie rozpoznanego znaku i odpowiednio reagować) - jeśli np rozpoznawanie “środkowej poziomej kreski” jest błędne, i użytkownik zwróci na to uwagę, w następnych porównaniach przesuwamy ją w odpowiednim kierunku.