Создайте приложение для распознавания номерных знаков с использованием Streamlit

Разработка приложения для распознавания номерных знаков с использованием Streamlit

Сводка

В этой статье кратко описывается решение по извлечению текста с лицензионных номерных знаков переменной длины с использованием предварительно обученной модели, а также разъясняется шаг за шагом, как создать веб-приложение с использованием Streamlit для предоставления этого решения пользователям.

Streamlit – это средство разработки открытого исходного кода, созданное специально для проектов машинного обучения и науки о данных.

Целевая аудитория

  • Ученые-данные, которые заинтересованы в изучении web-разработки, но считают, что жизнь слишком коротка, чтобы изучать HTML, CSS, JS.
  • Аспиранты-инженеры машинного обучения, которые заинтересованы в превращении своего кода на Python в долю веб-приложений.

Структура

  1. Обнаружение ближайшего камере номерного знака
  2. Использование easyocr или tesseract для извлечения текста
  3. Создание приложения для ввода изображения и вывода строки

Постановка проблемы

Учитывая 2D-изображение, сделанное с переменных углов, расстояний и условий освещения одного или нескольких транспортных средств, мы хотим извлечь номер лицензионного знака транспортного средства, находящегося ближе всего к камере. Все номерные знаки относятся к Сингапуру, что означает, что номер лицензионного знака состоит только из английских символов и цифр с одной или двумя линиями переменной длины.

Источник: Ваш полезный путеводитель по пойманной такси в Сингапуре, опубликованный в Executive Traveller.
  1. Обнаружение ближайшего номерного знака камере

Я использовал предварительно обученную модель yolov5 без настройки, потому что у меня нет данных. Вот мой код:

import yolov5import torchdef inference(    path2img: str,    show_img: bool = False,    size_img: int = 640,    nms_conf_thresh: float = 0.7,    max_detect: int = 10,) -> torch.Tensor:    model = yolov5.load("keremberke/yolov5m-license-plate")    model.conf = nms_conf_thresh    model.iou = 0.45    model.agnostic = False    model.multi_label = False    model.max_det = max_detect    results = model(path2img, size=size_img)    results = model(path2img, augment=True)    if show_img:        results.show()    return results.pred[0]

Наверняка вы задаетесь вопросом, почему я просто не устанавливаю max_detect равным 1 и не получаю непосредственно одну ограничивающую рамку вместо нескольких? Это потому, что каждая предсказанная ограничивающая рамка имеет оценку точности. С max_detect = 1, вы получаете наиболее уверенное прогнозирование, которое не всегда соответствует номерному знаку ближайшему к камере.

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

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

Получите номерной знак, ближайший к камере.

2. Используйте easyocr или tesseract для извлечения текста

Если ваш автомобильный номер имеет фиксированную длину и только одну строку, tesseract обычно достаточно. Однако, по моему опыту, он плохо справляется с цифрой 9 и символами Z, а иногда D.

Мой код приведен ниже. Пожалуйста, измените tessedit_char_whitelist и lang соответственно, если ваш автомобильный номер содержит не-английские символы.

import pytesseractdef ocr_tesseract(path2img):    text = pytesseract.image_to_string(        path2img,        lang="eng",        config="--oem 3 --psm 6 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",    )    return text

Он может успешно распознать номер автомобиля на одной строке, однако tesseract не может извлечь вторую строку для следующего изображения.

Источник: Toyota Wish Taxi в Сингапуре 23.9.2017, 2926, сделано Эльмаром

Этот красный номерной знак такси достаточно сложен для tesseract, потому что он содержит символы D, 9 и Z. Давайте попробуем вместо этого использовать easyocr!

easyocr вывод обнаружения

Несмотря на сложности, easyocr успешно распознал большинство символов, за исключением 5! Я определенно рекомендую easyocr вместо tesseract. Вот мой код:

def ocr_easyocr(path2img):    image = cv2.imread(path2img)    reader = easyocr.Reader(["en"], gpu=False)    detections = reader.readtext(image)    plate_no = []    [plate_no.append(line[1]) for line in detections]    return "".join(plate_no)

3. Создание приложения для загрузки изображения в качестве входных данных и вывода строки

И вот наступает самая интересная часть!

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

Чтобы еще больше разобраться в этом:

  • 3.1 Отобразить заголовок и подзаголовок
  • 3.2 Отобразить загрузчик файлов для пользователей для загрузки изображения
  • 3.3 Показать распознанный автомобильный номер в виде текста
  • 3.4 Отобразить загруженное изображение с прогнозируемым ограничивающим прямоугольником

3.1 Отобразить заголовок и подзаголовок

Сначала установим streamlit, запустив pip install streamlit.

Затем откройте Streamlit UI, запустив streamlit hello в терминале.

UI откроется в браузере по умолчанию. Приятного использования демо!

3.2 Отобразить загрузчик файлов для пользователей для загрузки изображения

Теперь добавим заголовок для нашего веб-приложения. Я создал скрипт на Python в папке src/ с названием app.py.

import streamlit as stdef app():    st.header("Web-приложение распознавания автомобильного номерного знака")    st.subheader("Питается YOLOv5")    st.write("Добро пожаловать!")if __name__ == "__main__":    app()

Затем я запустил команду streamlit run src/app.py в терминале.

Запустите ‘streamlit run <path>’ чтобы увидеть изменения в веб-приложении.

Обновите веб-страницу, вы увидите, что заголовок и подзаголовок появились! Вам не нужна HTML-синтаксиса!

Заголовок появился в веб-приложении Streamlit.

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

def app():    st.header("Веб-приложение распознавания номерных знаков")    st.subheader("Работает на YOLOv5")    st.write("Добро пожаловать!")    # добавить загрузчик файлов    with st.form("my_uploader"):        uploaded_file = st.file_uploader(            "Загрузить изображение", type=["png", "jpg", "jpeg"], accept_multiple_files=False        )        submit = st.form_submit_button(label="Загрузить")

Запустите команду streamlit run снова, и вы увидите, что загрузчик файлов появился. Вам не нужны никакие стили CSS.

Был добавлен загрузчик файлов.

3.3 Отображение распознанного номера автомобильного номерного знака в виде текста

После того, как пользователи загрузят изображение (событие: нажатие кнопки загрузки), мы можем использовать соответствующие функции Python для выполнения вывода. Номер автомобильного номерного знака будет отображаться в виде текста.

def app():    st.header("Веб-приложение распознавания номерных знаков")    st.subheader("Работает на YOLOv5")    st.write("Добро пожаловать!")    with st.form("my_uploader"):        uploaded_file = st.file_uploader(            "Загрузить изображение", type=["png", "jpg", "jpeg"], accept_multiple_files=False        )        submit = st.form_submit_button(label="Загрузить")    if uploaded_file is not None:        # сохранить загруженное изображение        save_path = os.path.join("temp", uploaded_file.name)        with open(save_path, "wb") as f:            f.write(uploaded_file.getbuffer())    if submit:        # отобразить номер автомобильного номерного знака как текста        text = run_license_plate_recognition(save_path).recognize_text()        st.write(f"Обнаруженный номер автомобильного номерного знака: {text}")if __name__ == "__main__":    app()
Отображение извлеченного номера автомобильного номерного знака в виде текста.

3.4 Отображение загруженного изображения с предсказанным ограничительным прямоугольником

Несмотря на то, что у нас есть и вход, и вывод в веб-приложении, этого недостаточно. Будет лучше, если мы сможем показать пользователям изображение, которое они загрузили, с ограничительным прямоугольником. Добавив небольшой виджет, мы сможем заверить пользователей, что прогноз был выполнен для правильного транспортного средства. Особенно когда прогноз неидеален, пользователям будет легче понять различия.

Источник: Руководство по фиксированным тарифам и тарифам такси Сингапура, автор Dinesh Dayani

Чтобы сделать его более интерактивным, я добавлю спиннер во время обработки запроса.

Спиннер был добавлен.

После завершения обнаружения, изображение будет отображено ниже.

Веб-приложение распознавания номерных знаков выглядит отлично!

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

Чтобы просмотреть репозиторий кода, пожалуйста, перейдите по этой ссылке.

Подпишитесь на меня в LinkedIn | 👏🏽 для моей истории | Подпишитесь на меня в VoAGI