Rozpoznawanie znaków i częściowy sukces – współczynnik korelacji #2

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.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *