Ни для кого не секрет, что Python прочно занял первенство в ML и Data Science. А что если посмотреть на другие языки и платформы? Насколько в них удобно делать аналогичные решения? К примеру, распознавание текста на картинке.  Среди текущих решений одним из наиболее распространённым инструментом является tesseract. В Python для него существует удобная библиотека, а для первоначальной обработки изображений, как правило, используется OpenCV. Для обоих этих инструментов есть исходные C++ библиотеки, поэтому их также возможно вызывать и из других экосистем. Попробуем это сделать в jvm и, в частности, на Kotlin. Первым делом установим tesseract. Его нужно установить отдельно на систему, согласно описанию из wiki. После установки можно проверить, что tesseract работает следующим образом: Где --tessdata-dir — путь до файлов tesseract (/usr/local/share/tessdata/ в macos). В случае успешной установки в stdout будет выведен распознанные текст. После этого можно подключить tesseract в jvm и сравнить результат работы с нативным вызовом. Для этого подключим библиотеку: После подключения библиотеки доступ к tesseract становится простым. Вызов той же команды из примера выше будет выглядеть следующим образом:  Как видно, практически все команды совпадают с используемыми в вызове из командной строки. Но, как минимум, на macos нужно ещё дополнительно настроить системную переменную jna.library.path, в которую нужно добавить путь до dylib-библиотеки tesseract.  После всех настроек можно попробовать запустить распознавание для того же файла и результат должен полностью соответствовать вызову из командной строки.  Перейдём теперь к обработке изображений с OpenCV. В Python для работы с ней не требуется ставить каких-либо дополнительных инструментов, кроме пакета в pip. В описании OpenCV под java указан порядок установки, когда всё ставится отдельно. Для самой jvm-экосистемы подход, когда требуются установки каких-либо нативных библиотек, не совсем привычен. Чаще всего если зависимости требуется какие-либо дополнительные библиотеки, то либо она сама их скачивает (как, например, djl-pytorch), либо при подключении через систему сборки внутри себя уже содержит библиотеки под различные операционные системы. К счастью, для OpenCV есть такая сборка, которой и воспользуемся: Перед началом работы с OpenCV потребуется подгрузить нативные библиотеки через: После чего можно использовать все доступные инструменты. Как, например, конвертация изображения в чёрно-белый цвет:  Как вы уже обратили внимание, аргументом для OpenCV выступает Mat, который представляет из себя основной класс-обёртку вокруг изображения в OpenCV в jvm, похожий на привычный BufferedImage.  Сам экземпляр Mat можно получить привычным для Python кода вызовом imread: В таком виде экземпляр можно дальше передавать в OpenCV и проделывать с ним различные манипуляции. Но для Java общепринятым является BufferedImage, вокруг которого, как правило, уже может быть выстроен pipeline загрузки и обработки изображения. В связи с чем возникает необходимость конвертации BufferedImage в Mat: И обратной конвертации Mat в BufferedImage: В частности, тот же tesseract в методе doOCR поддерживает как файл, так и BufferedImage. Используя вышеописанные преобразования, можно вначале обработать изображения с помощью OpenCV, преобразовать Mat в Bufferedimage и передать подготовленное изображение на вход tesseract. Попробуем теперь на практике собрать рабочий вариант приложения, который сможет найти текст на следующей картинке: Для начала проверим результат нахождения текста на изображении без обработки. И вместо метода doOCR будем использовать getWords, чтобы получить ещё confidence (score в Python-библиотеке) для каждого найденного слова: В результате будет найден только разный «мусор»: Если внимательней посмотреть на изображение, то можно увидеть, что шрифт для текста белый, а значит, можно попробовать использовать threshold вместе с последующей инверсией, чтобы оставить текст только на картинке: Пробуем следующие преобразования: После них посмотрим на картинку в результате (которую можно сохранить в файл через Imgcodecs.imwrite("output.jpg", mat) ) Теперь если посмотреть на результаты вызова getWords, то получим следующее: Как видно, весь текст успешно распознался.  Итоговый код по обработке изображения будет выглядеть следующим образом: Если сравнить полученный код с Python-версией, то разница будет минимальная. Производительность тоже должна быть практически сравнимой (за исключением, быть может, чуть больших преобразований изображения между Mat и BufferedImage).  Преимущество Python в рамках текущего примера будет только в бесшовной передаче изображений между OpenCV и tesseract. Экосистема Python сама по себе удобна тем, что все библиотеки общаются одними и теми же типами.  В jvm-экосистеме тоже есть свои преимущества. Это и статическая типизация, и многопоточность, и общая скорость работы вместе с наличием огромного количества инструментов под любые требования. Может, текущий пример не сильно раскрывает все преимущества, но, как минимум, он демонстрирует, что для данной задачи решение на jvm и Kotlin получается ничуть не сложнее. Python на текущий момент, беcспорно, лидер в ML. И в первую очередь все инструменты и библиотеки появляются на нём. Тем не менее, в других экосистемах можно использовать те же инструменты. Особенно учитывая, что если что-то есть под Python, то должна быть и нативная библиотека, которую можно легко подключить.  Надеюсь, что в этой статье вы нашли для себя что-нибудь полезное и новое. Спасибо за внимание, и напоследок несколько полезных ссылок: djl.ai — Deep Learning на jvm, где можно подключать модели из pytorch и tensorflow
deeplearning4j.org — аналогичное решение с возможностью обучать модели и импортировать существующие на tensorflow и keras
kotlinlang.org/docs/reference/data-science-overview — разные полезные вещи по Data Science на Kotlin (и Java) Весь код доступен в репозитории. Разработчик