Połowiczny sukces – program rozpoznaje znaki, ale jeszcze nie w 100% poprawnie.
Po kilku godzinach walki ze złośliwością rzeczy martwych (instalacja Linuxa obok Windowsa 10 przy aktywnym UEFI) udało mi się w końcu rozbudować kod o funkcję rozpoznawania znaków.
W poprzednim poście opisałem teoretyczne podstawy metody rozpoznawania znaków, którą wcieliłem w życie przy okazji dzisiejszego wpisu. Jednak aby skorzystać ze współczynnika korelacji potrzebowałem jakiegoś punktu odniesienia do fragmentów obrazu ze znakami.
Potrzebowałem zbioru wzorców. Zdobyłem je w sposób dość prosty, ale męczący – zrobiłem zdjęcie paragonu, po czym powycinałem poszczególne znaki i podrasowałem je w programie graficznym. Brakuje mi jeszcze małych liter, ale ich zdobycie nie powinno powodować trudności.
Przy starcie aplikacji wczytuję całą dostępną bibliotekę znaków i konwertuję je na wektory znormalizowane, które są przechowywane w pamięci. Posłużą potem za punkt odniesienia.
Fragmenty obrazu do rozpoznania znaków są pobierane z obrazu źródłowego przy pomocy metody submat(Rect roi) wywoływanej na obiekcie typu Mat.
Użyte przeze mnie wywołanie:
Mat letterImage = image.submat(new Rect(letter.getX(), letter.getY(), letter.getWidth(), letter.getHeight()));
Następnie wykonuję dość prostą funkcję recogniseUsingCorrelation(Mat letter).
Oto jej treść:
public String recogniseUsingCorrelation(Mat letter) { String character = null; double max = -1; for (CharacterPattern pattern : patternProvider.getCharacterPatterns()) { Mat destination = new Mat(); Imgproc.resize(letter, destination, new Size(pattern.getWidth(), pattern.getHeight())); destination = basicImageOperations.binarizeColorImage(destination); double[] letterImageVector = basicImageOperations.getNormalizedBinaryImageVector(destination); double scalarProduct = calculateScalarProduct(letterImageVector, pattern.getVector()); if (scalarProduct > max) { character = pattern.getCharacter(); max = scalarProduct; } } return character; }
W pętli iterującej po liście wzorców skaluję obraz ze znakiem do rozpoznania do wymiarów wzorca. Następnie konwertuję go do wektora znormalizowanego i obliczam iloczyn skalarny.
Przyjmuję, że największa wartość iloczynu skalarnego powinna odpowiadać znakowi, który jest na badanym fragmencie.
Co prawda nie uzyskuję jeszcze 100% skuteczności, a także pomijam białe znaki, ale nic nie powoduje takiego poczucia dumy jak rozpoznany napis „PARAGON FISKALNY”. Kod i wzorce oczywiście wymagają jeszcze dopracowania oraz upiększenia, ale na to przyjdzie czas w nadchodzącym tygodniu.