Как найти нестандартное решение, чтобы потом отказаться от него

Превью
Превью

Кейс

Хочу продолжить рассказывать про своего бота, но с погружением в примененные технологии. В этой статье я бы хотел поделиться кейсом решения одной нетривиальной задачи для Taxi Watcher — распознаванием текста со скриншота приложения.

Хронология событий

Когда я начинал писать бота, в процессе появился резонный вопрос: а как пользователь будет устанавливать адрес? Я решил пойти по простому пути и нашел топорное решение, которое первое время использовалось (и до сих пор работает) — добавление адреса вручную, текстом.

Затем понял, что это хоть и достаточно точно работает, но однозначно неудобно, ведь пользователю нужно время, чтобы вписать адрес.

И случайным образом я прихожу к такому решению: можно ведь распознавать текст прямо со скриншота из приложения такси.

Внедрение

Конечно, решение не идеальное: нужно время, чтобы зайти в приложение, сделать скриншот, потом вернуться, обрезать (чтобы не было лишнего в распознанном тексте) и отправить. Не много ли действий? Однозначно много, но не так топорно, как с добавлением адреса вручную.

Про саму технологию

После недолгого гугления нашел библиотеку, которая может это сделать — pytesseract и OpenCV.

И тут появляются свои проблемы: начиная от написания алгоритмов, которые будут отбрасывать лишний текст, заканчивая развёртыванием на сервере.

Начало работы с изображением:

# Получение изображения от пользователя photo = message.photo[-1] photo_data = await bot.get_file(photo.file_id) photo_path = photo_data.file_path # Получение расширение файла и добавление имени для временного хранения (после обработки, изображение удаляется) _, file_extension = os.path.splitext(photo_path) file_name = f"photo{file_extension}" await photo_data.download(file_name)

Я выделил ряд проблем, с которыми столкнулся. Начнем по порядку.

  • Проблема первая: как отбросить лишнее?

Для решения этой задачи я решил воспользоваться регулярными выражениями:

# Считывание изображения image = cv2.imread(file_name) # Преобразование изображения в оттенки серого gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Применение различных фильтров для улучшения распознавания blurred = cv2.GaussianBlur(gray, (5, 5), 0) thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] # Собственно, распознавание текста с изображения ocr_text = pytesseract.image_to_string(gray, lang='rus')

Дальше интереснее, потому что некоторые элементы распознаются как текст. Например, как на картинке ниже:

Пример скриншота
Пример скриншота
# Разбивка текста на отдельные слова и формирование списка частей адреса text_parts = ocr_text.split() address_parts = []

Я написал такой, неоднозначный метод, чтобы убрать лишние элементы:

current_address = "" for part in text_parts: if part != "Подъезд" and part != "О" and part != "0": current_address += part + " " else: if current_address: address_parts.append(current_address.strip()) current_address = ""

Далее, идет финальная обработка распознанных адресов, при помощи всё тех же регулярных выражений:

final_address_parts = [] for part in address_parts: part = re.sub(r'-\s*\w+\s*\+', '', part) final_address_parts.append(part)

И финальный момент для второй части адреса: к 1-му и 2-му приписывается город Москва (все же столица, как никак):

final_address_parts[0] += ', Москва' final_address_parts[1] += ', Москва'
  • Проблема вторая: как пользователю указать город?

Таким образом, мы плавно переходим ко второй проблеме: ботом пользуются в разных регионах (и странах), а такая функция лишь для жителей столицы... Ну такое. Это лишь сужает регион использования и его удобство. Я так и не нашел решения, ведь в приложении просто адреса, без города (что тоже логично, ведь он не нужен), а просить пользователя указать еще и город — опять таки, создает лишние действия.

  • Проблема третья: как пользователю подсказать, что и как отправлять?
Пример скриншота
Пример скриншота

Хоть я и сделал пример, и при каждом распознавании он отправлялся в чат, это создавало трудности: все же, это не делает использование бота интуитивно понятным, а также сбивает с толку. Всё же, пользователь не хочет думать и это факт, поэтому это ещё один камень в огород использования этого решения.

  • Проблема четвёртая: развёртывание на сервере

Тут уже полностью моя вина и неопытность. Когда я арендовал VPS сервер, я выбрал Debian 10, и думал, что это ни на что не повлияет, однако это оказалось не так: начиная с отсутствия нужной версии Python (3.10+), до неимения нужной версии pytesseract (на локальной машине 5.3.0, а на сервере 3.0.0). Из-за последнего и началось интересное: распознавание идёт несколько иначе, и нужно было либо править, либо убирать часть уже написанных алгоритмов.

Последствия упразднения

По итогу, сейчас эта технология убрана и не используется, ведь ей на смену пришла идея отправлять геопозицию прямо в Телеграм и работать напрямую с координатами, но, как кейс, эта идея живёт. И я думаю, что в скором времени смогу применять его для решения уже других, более сложных задач.

Итог

Решение поставленной задачи было интересным и чем-то совсем новым, поскольку я никогда не занимался распознаванием текста, и стоит отметить: это получилось занимательным и увлекательным.

11
Начать дискуссию