С помощью Teseract получить координаты текста

sikuli
Теги: #<Tag:0x00007fedb979b2e8>

(S Romankov) #1
   Элемент с текстом не доступен для WebDriver, необходимо получить координаты текста

для последующего нажатия на кнопку содержащую данный элемент.
Для решения задачи подключил Teseract - на данный момент добился получения текста со всей страницы. Для получения координат использую код ниже. На строчке api.TessPageIteratorBegin(pi);

Выдает exception java.lang.Error:

Invalid memory access
at com.sun.jna.Native.invokeVoid(Native Method)
at com.sun.jna.Function.invoke(Function.java:367)
at com.sun.jna.Function.invoke(Function.java:315)
at com.sun.jna.Library$Handler.invoke(Library.java:212)
at com.sun.proxy.$Proxy9.TessPageIteratorBegin(Unknown Source)

   TessAPI  api = LoadLibs.getTessAPIInstance();
    TessAPI.TessBaseAPI handle = api.TessBaseAPICreate();

    String lang = "eng";
    File toast = new File("src/test/ToastScreenShoots/image.png");
    BufferedImage image = null;
    try {
        image = ImageIO.read(new FileInputStream(toast));
    } catch (IOException e) {
        e.printStackTrace();
    }
    ByteBuffer buf = ImageIOHelper.convertImageData(image);
    File file = new File("src/test/ToastScreenShoots/image.png");
    api.TessBaseAPIInit3(handle, "tessdata", lang);
    TessAPI.TessResultIterator ri = api.TessBaseAPIGetIterator(handle);
    TessAPI.TessPageIterator pi = api.TessResultIteratorGetPageIterator(ri);

    api.TessPageIteratorBegin(pi);
    System.out.println("Bounding boxes:\nchar(s) left top right bottom confidence font-attributes");

    int height = image.getHeight();
    do {
        Pointer ptr = api.TessResultIteratorGetUTF8Text(ri, TessAPI.TessPageIteratorLevel.RIL_WORD);
        String word = ptr.getString(0);
        api.TessDeleteText(ptr);
        float confidence = api.TessResultIteratorConfidence(ri, TessAPI.TessPageIteratorLevel.RIL_WORD);
        IntBuffer leftB = IntBuffer.allocate(1);
        IntBuffer topB = IntBuffer.allocate(1);
        IntBuffer rightB = IntBuffer.allocate(1);
        IntBuffer bottomB = IntBuffer.allocate(1);
        api.TessPageIteratorBoundingBox(pi, TessAPI.TessPageIteratorLevel.RIL_WORD, leftB, topB, rightB, bottomB);
        int left = leftB.get();
        int top = topB.get();
        int right = rightB.get();
        int bottom = bottomB.get();
        System.out.print(String.format("%s %d %d %d %d %f", word, left, top, right, bottom, confidence));

        IntBuffer boldB = IntBuffer.allocate(1);
        IntBuffer italicB = IntBuffer.allocate(1);
        IntBuffer underlinedB = IntBuffer.allocate(1);
        IntBuffer monospaceB = IntBuffer.allocate(1);
        IntBuffer serifB = IntBuffer.allocate(1);
        IntBuffer smallcapsB = IntBuffer.allocate(1);
        IntBuffer pointSizeB = IntBuffer.allocate(1);
        IntBuffer fontIdB = IntBuffer.allocate(1);
        String fontName = api.TessResultIteratorWordFontAttributes(ri, boldB, italicB, underlinedB,
                monospaceB, serifB, smallcapsB, pointSizeB, fontIdB);
        boolean bold = boldB.get() == TessAPI.TRUE;
        boolean italic = italicB.get() == TessAPI.TRUE;
        boolean underlined = underlinedB.get() == TessAPI.TRUE;
        boolean monospace = monospaceB.get() == TessAPI.TRUE;
        boolean serif = serifB.get() == TessAPI.TRUE;
        boolean smallcaps = smallcapsB.get() == TessAPI.TRUE;
        int pointSize = pointSizeB.get();
        int fontId = fontIdB.get();
        System.out.println(String.format("  font: %s, size: %d, font id: %d, bold: %b," +
                        " italic: %b, underlined: %b, monospace: %b, serif: %b, smallcap: %b",
                fontName, pointSize, fontId, bold, italic, underlined, monospace, serif, smallcaps));
    } while (api.TessPageIteratorNext(pi, TessAPI.TessPageIteratorLevel.RIL_WORD) == TessAPI.TRUE);

(Vasiliy Rakshin) #2

Так если вы используете Сикули, и у вас есть изображение этой кнопки, так нажимайте на неё с помощью Сикули.


(S Romankov) #3

Я не использую Sikuli, использую чистый Teseract


(Vasiliy Rakshin) #4

Извините, но на мой взгляд, это изврат (я имею ввиду способ нажатия на кнопку через распознавание текста на экране и координат).
И тег sikuli тогда лишний.


(S Romankov) #5

Возможно кто-то разбирался с Sikuli глубже чем просто вызывал его методы поэтому и тег. Тут например модератор Сергей Король он помоему один из контрибьютеров Sikuli, так что продолжаю надеятся на помощь


(Sergey Korol) #6

У Tesseract точность распознавания весьма посредственна при большой области анализа. Ну и множество второстепенных факторов могут влиять на качество. Я бы его не использовал для парсинга web страниц.

SikuliX работает с изображениями на базе opencv. Если кнопка визуально уникальна на странице, то проблем с идентификацией (даже ввиду динамики изменения текста) не будет. Достаточно будет поиграться с уровнем similarity.

В качестве альтернативы можно привязываться к какому-то уникальному якорю и осуществлять попиксельное смещение вверх / вниз / влево / вправо (SikuliX это позволяет делать).

Но тут тоже есть свои подводные камни. При смене разрешения / битности ваши тесты будут падать. Т.е. нужно либо обеспечить неизменность разрешения, либо создать выборку expected images в разных разрешениях, и искать по первому совпадению.

Плюс ко всему, OCR тулы весьма требовательны к наличию active desktop. В headless режиме не получится с ними взаимодействовать.

П.С. А что за задачу вы решаете? Просто интересно, неужели действительно невозможно получить локатор без OCR тулов? Может проще обратиться к девелоперам с соответствующей просьбой, прежде чем прибегать к столь радикальным подходам?