ORCP - это проект, цель которого - автоматизировать процесс идентификации автомобилей и определения их стоимости с использованием технологии оптического распознавания. Этот проект включает в себя: сбор данных, обучение моделей и развёртывание Telegram бота для предоставления пользователям информации о марке и модели автомобиля, а так же его стоимости на основе фотографий автомобиля.
Суть: Пользователь отправляет фото автомобиля в Telegram бот ORCP, а бот используя обученную нейросеть классификации и детекции, определяет какая это марка, модель и поколение, а так же указывает рыночную стоимость автомобиля с помощью отобранных данных, загруженных с сайта "auto.ru".
Примеры, в которых ORCP справился лучше в классификации авто, чем умная камера Алисы.
Умная камера Алисы НЕ верно определила авто:
Умная камера Алисы НЕ смогла определить модель авто: ![]() |
Умная камера Алисы НЕ смогла определить модель авто: ![]() |
Ссылки:
- Бот ORCP в Telegram
- Веса моей модели классификации YOLOv8x
- Стоковые веса модели классификации YOLOv8x
- Стоковые веса модели детекции YOLOv8x
- Датасет загруженных авто
- Ссылки на фото китайских авто
- Загруженные фото китайских авто для модели
- Отобранные фото китайских авто для модели
- ORCP — Optical Recognition of Cars and Prices
ORCP включает в себя три основных этапа разработки:
- Сбор данных: Написание парсера, который сохраняет информацию об авто по различным параметрам: стоимость, объём двигателя, транспортный налог и т.д. Помимо этого парсер сохраняет ссылки на фотографии авто в текстовые файлы для дальнейшего обучения.
- Обучение модели: Используя скачанные ссылки, загрузка фотографий автомобилей, отбор подходящих фотографий для обучения, разделение на обучающую и тестовую выборки и обучение на этих данных модели.
- Telegram bot: Реализация Telegram бота, позволяющего взаимодействовать с пользователями. Пользователи могут отправлять фотографии боту, который используя обученные модели, будет предоставлять информацию о марке, модели, годах выпуска и стоимости авто.
Использовать репозиторий ORCP можно по разному, по этому напишу отдельно про каждый этап. Как уже было указано выше, данный проект разделён на 3 раздела. У каждого раздела, есть своя папка, которая находится в SRC, а именно Parsing, YOLOv8 и Bot. Основные детали при их использовании будут указаны ниже.
В папке Parsing, есть несколько модулей, с помощью которых можно загружать информацию об автомобилях с сайта "auto.ru". Здесь будут указаны необходимые библиотеки, которые нужны для запуска парсера, а так же дополнительное ПО.
Для более подробного описания, а так же просмотра логики парсинга, откройте пункт Data Collection
Парсер будет корректно работать, только при выполнении всех условий ↓ УКАЗАННЫХ НИЖЕ ↓
fake_useragent - замена агента браузера, при парсинге
user_agents - фильтрация мобильных агентов
requests - запросы на сайт
tqdm - подсчёт оставшегося времени, при парсинге
random - генерация случайных чисел, при смене IP
genericpath - проверка существования папки
sys - импорт модулей из разных папок
os - указание пути для файлов
time - подсчёт затраченного времени
csv - сохранение csv файлов
Для постоянного изменения IP во избежании появления капчи использовался: Tor "луковый" браузер. Без данного ПО, код работать НЕ будет!
Для того, чтобы контролируемо менять IP адрес нужно:
- Установить "луковый" браузер
- В папке "лукового" браузера найти конфигурационный файл torrc
- В данном файле прописать дополнительные порты. Я добавил 100 портов, начиная с "SocksPort 9050" и заканчивая "SocksPort 9149". Каждый порт должен идти с новой строчки. Сохранить torrc.
- Перед парсингом нужно: запустить и подключиться к сети "луковым" браузером. Браузер должен быть подключен к сети одним из мостов (obfs4).
Парсер будет корректно работать, только при выполнении всех условий ↑ УКАЗАННЫХ ВЫШЕ ↑
В качестве основы, для классификации и детекции автомобилей, мне послужила модель нейросети YOLOv8.
Для более подробного описания загрузки данных, а так же обучения модели, откройте пункт Model Training - YOLOv8
torch == 2.0.1 - фреймворк для работы с нейросетями
nvidia-cuda == 11.7 - для использования видеокарт nvidia при обучении
ultralytics - для импорта модели YOLO
requests - для запросов на сайт
os - указание пути файлов
shutil - создание копий исходных файлов
time - подсчёт затраченного времени
random - генерация случайных числе, при выборе train/test
- OS: Manjaro Linux 23.0.3 Uranos, GNOME 44.5, Core 6.1.55-1-MANJARO
- GPU: Nvidia RTX 2070 8Gb
- Nvidia driver: 470.199.02, CUDA 11.4 (Pre-installed)
- CUDA: 11.8 (Installed after Nvidia driver)
- CUDNN: 8.6 (Installed after CUDA)
- Python: 3.10.12
Для использования Telegram бота, основным инструментом была библиотека aoigram 3.0 и библиотека asyncio - для выполнения асинхронных задач.
Для более подробного описания реализации Telegram бота, откройте пункт Telegram Bot
torch == 2.0.1 - фреймворк для работы с нейросетями
nvidia-cuda == 11.7 - для использования видеокарт nvidia при обучении
ultralytics - для импорта модели YOLO
aiogram == 3.00 - для использования Telegram API
asyncio - для асинхронных функций бота (приём сообщений, фото и т.д.)
pandas - для работы с csv файлами
sys - импорт модулей из разных папок
os - указание пути для файлов
time - подсчёт затраченного времени
datetime - сохранение фото в формате Y-m-d_H-M-S
В данном разделе находится подробное описание парсинга различных автомобильных параметров, таких как: тип кузова, объём двигателя, стоимость и т.д. А так же парсинга ссылок на фотографии, с помощью которых возможно дальнейшее обучение модели классификации.
Для сбора данных мной был выбран сайт "auto.ru", так как это один из самых популярных сайтов для продажи авто. На момент парсинга (август 2023) на данной площадке было ≈370 000 объявлений о продаже авто, а на момент написания README (октябрь 2023) ≈410 000 объявлений.
В результате парсинга мной было загружено: 376 094 автомобиля - все машины, включая китайские. Количество уникальных автомобилей в данных объявлениях: 96 981. Количество различных брендов авто - 89, моделей - 1835, поколений - 4203. Общий объём текстовых файлов в виде ссылок на фотографии ≈ 900 МБ.
Для использования парсера, нужно выполнить все пункты в разделе Usage → Parsing, а именно: установку "лукового" браузера, открытие портов и т.д. Перед парсингом необходимо запустить "луковый" браузер и подключиться, через него к сети используя мосты.
Для удобства использования, все модули и данные имеющие отношение к парсингу расположены в: SRC/Parsing. А все модули python для парсинга находятся в папке: SRC/Parsing/Proxy, так как для парсинга используется proxy. Кроме того в данном разделе, модули специально названы в алфавитном порядке, для удобного последовательного запуска. Рекомендуемый порядок запуска: a1.., a2.., b1.., c1.. и т.д.
Бренд → Модель → Поколение → Страница → Объявление → Данные
В файле brands.txt - список всех брендов:
Бренды → SRC/Parsing/Results/Cars/Brands/brands.txt
У каждого бренда свой файл с моделями, в данном файле все модели конкретного бренда:
Модели → ORCP/SRC/Parsing/Results/Cars/Models/БРЕНД.txt, примеры:
Модели бренда Toyota: SRC/Parsing/Results/Cars/Models/TOYOTA.txt, Модели бренда Haval: SRC/Parsing/Results/Cars/Models/HAVAL.txt - и т.д.
У каждой модели свой файл с названиями поколений, в данном файле все поколения конкретной модели:
Названия поколений → SRC/Parsing/Results/Cars/Generations_names/БРЕНД_МОДЕЛЬ.txt, примеры:
Поколения модели Audi A4: SRC/Parsing/Results/Cars/Generations_names/AUDI_A4.txt Поколения модели Geely Coolray: SRC/Parsing/Results/Cars/Generations_names/GEELY_COOLRAY.txt
У каждой модели свой файл с кодами поколениями (для датасета), в данном файле все поколения конкретной модели:
Коды поколений → SRC/Parsing/Results/Cars/Generations/БРЕНД_МОДЕЛЬ.txt, примеры:
Поколения модели Audi A4: SRC/Parsing/Results/Cars/Generations/AUDI_A4.txt Поколения модели Geely Coolray: SRC/Parsing/Results/Cars/Generations/GEELY_COOLRAY.txt
Папка для хранения бэкапов:
BackUps → SRC/Parsing/Results/Cars/BackUps
Папка для быстрого продолжения парсинга, при возникновении ошибок:
Parsing_failure - SRC/Parsing/Results/Cars/Parsing_failure
Более подробное описание будет ↓ ниже ↓
После того, как все условия использования были выполнены, можно проверить корректно ли работают порты. Для этого вы можете запустить файл: Helper/tor_ip.py и если при каждом новом запуске ваш IP изменяется, то всё было настроено верно.
Если всё работает, то можно приступить к подготовке к парсингу. Начать следует с модуля a1_preparation_to_parsing_PROXY.py. В данном файле нужно:
- Добавить модуль, в системный путь python (sys.path.append...) изменить на свой путь
- Изменить переменную заголовка header, на актуальную. В противном случае капча будет постоянно прерывать парсинг. Для этого нужно:
- Открыть сайт "auto.ru", и перейти в раздел объявления
- Выбрать любую марку и модель авто, затем нажать на кнопку показать n предложений
- Открыть инструменты разработчика (обычно f12), затем выбрать пункт сеть
- Прокрутить страницу вниз и нажать на кнопку любой следующей страницы в поиске (например 2)
- После загрузки страницы в инструментах разработчика для удобства отфильтровать данные по убыванию размера и нажать на файл .json с названием "listing"
- Выбрать пункт заголовки и в нём найти подпункт: заголовки запроса
- Нажать на кнопку необработанные заголовки при наличии и скопировать все заголовки
- Вставить заголовки в переменную header
- Удалить одну или несколько первых строк, так, чтобы первая строка была: "Host: auto.ru"
Запустите данный python модуль и если вы видите в терминале, вывод .json файла и далее надпись: "The header is set correctly!!!" - значит вы выполнили всё верно.
После того, как подготовка была успешно завершена, можно приступить к парсингу. Для этого нужно запустить модуль: a2_parsing_brands_PROXY.py, который будет парсить 99 страниц сайта - это максимальное количество отображаемых страниц. На каждой странице расположены несколько объявлений, чаще всего их 37. При нахождении бренда, который ещё не был записан, он записывается в отдельный файл.
Логика:
Первый цикл бежит по 99 страницам, отсортированных по дате размещения, второй цикл бежит по объявлениям авто на каждой странице ~37 объявлений с авто, и если бренда ещё не было в списке, то добавить бренд в список и сохранить в список. Файл называется brands.txt, находится в папке: SRC/Parsing/Results/Cars/Brands/brands.txt
Рекомендую сразу дублировать загруженные данные в папку: SRC/Parsing/Results/Cars/BackUps, так как это будет удобно использовать в повторных парсингах при ошибках.
При необходимости можно изменить сортировку авто, для этого нужно изменить значение ключа "sort" в переменной params. Примеры сортировок: cr_date-desc - по дате размещения, autoru_exclusive-desc - по уникальности, fresh_relevance_1-desc - по актуальности
После того, как бренды были загружены в файл brands.txt, можно парсить сайт по моделям. Для этого нужно запустить модуль: b1_parsing_models_PROXY.py
Логика:
Первый цикл бежит по списку с брендами, который уже был загружен, второй цикл бежит по списку доступных страниц для данного бренда, третий цикл по объявлениям ~ 37 на странице. Если модели ещё не было, то сохранить в файл с названием бренда. Сортирую авто по уникальности.
Примеры: SRC/Parsing/Results/Cars/Models/GEELY.txt, SRC/Parsing/Results/Cars/Models/HAVAL.txt
Во время парсинга моделей сохраняется файл, в котором будет указано, какие бренды и модели уже были загружены. Он расположен в: SRC/Parsing/Results/Cars/Parsing_failure/Models_fail.txt. При возникновении ошибки можно воспользоваться данным файлом,и удалить из файла brands.txt уже загруженные бренды, чтобы повторно не парсить одно и тоже. Не забывайте делать backup файлов перед его редактированием (дублирование в папку BackUps), потому что в дальнейшем, они понадобятся в исходном виде!
После того, как были загружены бренды и модели, можно парсить сайт по поколениям данных автомобилей. Для этого нужно запустить модуль: c1_parsing_generations_PROXY.py
Логика:
Первый цикл бежит по списку с брендами, второй цикл по списку моделей, третий по страницам модели, четвёртый по объявлениям на каждой странице. Если поколения ещё не было, то сохранить в файл с названием бренда и модели. В папку Generations сохраняются закодированные названия поколений. Пример: SRC/Parsing/Results/Cars/Generations/HAVAL_F7.txt (21569049, 23206512). В папку Generations_names сохраняются названия поколений. Пример: SRC/Parsing/Results/Cars/Generations_names/HAVAL_F7.txt (I, I Рестайлинг)
Во время парсинга поколений сохраняется файл, в котором будет указано, какие бренды модели и поколения уже были загружены. Он расположен в: SRC/Parsing/Results/Cars/Parsing_failure/Generations_fail.txt. При возникновении ошибки можно воспользоваться данным файлом,и удалить из файла brands.txt уже загруженные бренды, и модели из файла с моделями, чтобы повторно не парсить одно и тоже. Не забывайте делать backup файлов перед его редактированием (дублирование в папку BackUps), потому что в дальнейшем, они понадобятся в исходном виде!
После того, как были загружены бренды, модели и поколения можно приступить к парсингу всех автомобилей. Парсинг включает в себя 39 различных параметров, таких как: стоимость, объём двигателя, транспортный налог, тип кузова, разгон до сотни и многие другие. По мимо парсинга параметров авто, одновременно с ним происходит парсинг фотографий авто, а именно ссылок на фотографии. Ссылки на фото сохраняются в разных файлах с тремя разными разрешениями фотографий, а именно: 320x240, 456x342, 1200x900. Для парсинга нужно запустить модуль: d1_parsing_all_cars_PROXY.py
Если вы корректировали файлы с брендами, моделями и поколениями, при ошибках в парсинге, то нужно заменить эти файлы, на оригинальные исходные файлы из папки BackUps
Логика:
Первый цикл бежит по списку с брендами, второй с моделями, третий с поколениями, четвёртый со страницами и пятый с объявлениями на каждой странице. Каждый автомобиль соответствует одной строке в csv файле. Данные сохраняются в файл: SRC/Parsing/Results/Data/all_cars.csv
Ссылки на фото сохраняются в папке: SRC/Parsing/Results/Photo_links
Структура файла с ссылками: БРЕНД_МОДЕЛЬ_ПОКОЛЕНИЕ_ГОД ВЫПУСКА-ГОД ОКОНЧАНИЯ-РАЗРЕШЕНИЕ ФОТО.txt
Например ссылки на Haval F7 I поколения в разрешении 320x240 сохраняются в файл: SRC/Parsing/Results/Photo_links/HAVAL/F7/HAVAL_F7_I_2018-2022-320x240.txt
На всякий случай я оставил в проекте модуль d2_parsing_all_cars.py. В нём дублирован модуль d1 с загрузкой всех авто, но без использования "лукового" браузера и прокси. Скорее всего данный модуль будет бесполезен, так как на октябрь 23 года, сайт "auto.ru" очень быстро блокирует (отправляет капчу) при парсинге с одного IP.
В данном разделе находится подробное описание загрузки фотографий из списка уже загруженных ссылок, селекция фото, анализ стоимости авто с созданием датасетов со средней стоимостью авто, а так же обучение нейронной сети, с помощью модели YOLOv8.
В результате для построения модели классифицирующей китайские авто было загружено: 68 564 фото (≈2.3ГБ), которые включали в себя 286 разных моделей китайских брендов. После отбора фото в модель попало 35 152 фото (≈1.2ГБ) и 134 разные модели китайских брендов.
Для удобства использования, все модули и данные имеющие отношение к загрузке фото и обучение модели YOLOv8 расположены в: SRC/YOLOv8, исключая папку Analysis. Кроме того в данном разделе, модули специально названы в алфавитном порядке, для удобного последовательного запуска. Рекомендуемый порядок запуска: a1.., a2.., b1.., c1.. и т.д.
Парсинг → Загрузка фото → Отбор фото → Обучение модели на фото
Для загрузки фотографий нужно воспользоваться модулем: a1_download_one_brand.py Для этого вам нужно указать в нём 3 параметра:
- Максимальное количество картинок для 1 модели авто - pictures_quantity
- Размер картинки - picture_size
- Бренд авто (название папки) - car_brand После того, как вы указали значения, во всех переменных, запустите модуль. Все фотографии будут загружены в папку: Downloads/CAR_BRAND/MODEL/БРЕНД_МОДЕЛЬ_ПОКОЛЕНИЕ_ГОД ВЫПУСКА-ГОД ОКОНЧАНИЯ-РАЗРЕШЕНИЕ ФОТО"** Если в текстовом файле с ссылками было менее 500 ссылок, то модуль скачает все доступные фото.
Пример пути сохранённой фото: Downloads/GEELY/COOLRAY/GEELY_COOLRAY_I_2019--456x342n/7.jpg
В своей модели я использовал "средний" вариант фото с разрешением 456x342. Для улучшения качества модели можно попробовать, работать с более высоким разрешением, но в таком случае на обучении модели потребуется гораздо больше времени, по этому рекомендую выбирать разрешение фото, в зависимости от производительности вашей системы.
Для того чтобы отобрать фотографии рекомендую сразу дублировать загруженные фотографии в папку: SRC/YOLOv8/Selected_photos
В данном случае для относительно качественного отбора, я вручную отбирал нужные фото, а ненужные удалял из папки Selected_photos
Критерии отбора:
- Только экстерьер (все фото салона, руля и тд - удалить)
- Не должно быть открытых элементов авто. (открытые двери, капот, багажник - удалить)
- Автомобиль должен полностью попадать в кадр (не должна быть обрезана часть автомобиля)
- Фотография не должна быть перевёрнута на 90/180 градусов, а так же сильно наклонена как по горизонтали, так и по вертикали.
- Фото должно быть сделано в светлое время суток, либо же при хорошем искусственном освещении (тёмные фото - удалить)
- В кадре должно быть минимальное количество посторонних предметов, а так же других авто (по возможности)
- Фотография должна быть хорошего качества (очень мыльные или зернистые фото - удалить)
- Узкие вертикальные фото - не подходят, (разрешение +- 130x320 - удалить)
- Общее количество фото 1 бренда, 1 модели и 1 поколения должно быть более 80 (если менее 80 - удалить целое поколение)
После того, как все фотографии были отобраны, и поколения, в которых менее 80 фото так же были удалены из папки /Selected_photos/ их нужно подготовить для модели YOLOv8, для этого нужно воспользоваться модулем b1_divide_photo.py. При запуске данного модуля все фото из папки: SRC/YOLOv8/Selected_photos будут копированы папку SRC/YOLOv8/Prepared_photos и там разделены по папкам train и test с соотношением 70/30. Помимо этого будет немного изменена структура пути к фото, а именно удалены папки бренда и модели из пути, например: Было в Selected_photos - SRC/YOLOv8/Selected_photos/HAVAL/F7/HAVAL_F7_I_2018-2022-456x342n/1.jpg ... 500.jpg - Стало в Prepared_photos/train - SRC/YOLOv8/Prepared_photos/train/HAVAL_F7_I_2018-2022-456x342n/1.jpg ... 350.jpg Стало в Prepared_photos/test - SRC/YOLOv8/Prepared_photos/test/HAVAL_F7_I_2018-2022-456x342n/351.jpg ... 500.jpg
Для обучения, потребуется скачать с официального сайта, модель yolov8 для классификации, а так же модель для детекции, она понадобится позже. На сайте есть разные варианты моделей от n - нано, самая маленькая модель, до x - extra. Я использовал YOLOv8x. После загрузки модели, помещаю их в Models/Classification/yolov8x-cls.pt - для классификации, и Models/Detection/yolov8x.pt - для детекции. Две модели нужны для того, чтобы сначала распознать (понять), есть ли на изображении авто, а уже после производить его классификацию.
После того, как модели были загружены и размещены в указанные выше директории, нужно воспользоваться модулем c1_fit_model.py.
В данном модуле можно изменить размер изображений, для обучения - imgsz и количество эпох обучения - epochs
В лучшей модели я использовал imgsz = 320, epochs = 80, хотя если смотреть по цифрам, то после 30 эпохи показатели модели, практически не улучшаются, но по субъективным ощущениям модель с 80 эпохами работает лучше, чем с 30.
После запуска модуля и обучения модели, будет создана папка с результатами обучения: runs/classify/train. Наилучшие веса модели будут в: runs/classify/train/weights/best.pt
После обучения рекомендую переименовать и перенести лучшую модель в папку: Models/Classification
С помощью модуля: SRC/YOLOv8/d1_predict_car.py можно классифицировать авто на локальной машине.
С помощью модуля: SRC/YOLOv8/d2_detect_car.py можно произвести детекцию авто на локальной машине.
Для того, чтобы подгружать среднюю стоимость авто, нужно воспользоваться модулем: Analysis/Prices/cost_collection.py При запуске данный модуль загружает собранные данные о всех машинах из файла: SRC/Parsing/Results/Data/all_cars.csv и создаёт 6 различных файлов со стоимостью авто, в зависимости от его статуса:
- BM.csv (Brands Models) - все модели. Используется, так как не у всех авто указано поколение
- BMG.csv (Brands Models Gens) - все модели со всеми указанными поколениями
- NBM.csv (New Brands Models) - только новые модели
- NBMG.csv (New Brands Models Gens) - только новые модели с указанными поколениями
- UBM.csv (Used Brands Models) - только подержанные модели
- UBMG.csv (Used Brands Models Gens) - только подержанные авто с указанными поколениями
В файле Analysis/PDA.ipynb краткий первичный анализ полученных данных.
В данном разделе находится структура бота, а так же описание его модулей. Данный бот работает с помощью библиотеки aiogram 3.0, а так же библиотеки асинхронных функция asyncio
Для удобства использования, все модули и данные имеющие отношение к настройке и запуску бота расположены в: SRC/Bot, исключая папку Analysis.
- main.py - основной связующий файл для запуска и работы бота.
- handlers.py - обработчики всех кнопок, а так же сообщений в боте в том числе и фотографий.
- detection.py - Детектирование авто на фотографии.
- predictions.py - При наличии авто на фото: определение бренда и модели авто, а так же загрузка данных о стоимости из ы.
- keybords.py - кнопки, реплай, а так же инлайн клавиатуры.
- settings.py - API ключ для телеграм бота.
Структура бота:
main.py → settings.py - импорт API ключа.
main.py → handlers.py → settings.py - импорт API ключа.
main.py → handlers.py → keyboards.py - импорт клавиатур.
main.py → handlers.py → detection.py - возврат результатов модели детекции.
main.py → handlers.py → predictions.py → /Analysis/ - возврат результатов модели классификации.
- Постоянная обработка сообщений от пользователя, как текстовых, так и нажатий на клавиатуры, а так же обработка фото
- При отправке пользователем фотографии, сначала она обрабатывается модулем detection.py, для того чтобы обнаружить или не обнаружить авто на фото.
- Если модель обнаружила авто на фото, то нужно отправить пользователю вероятности совпадения авто из модуля predictions.py, а так же данные о стоимости авто из одного из 6 .csv фалов, расположенных в папке: Analysis/Prices. Логика выбора прописана в файле predictions.py
Для запуска бота потребуется:
- Открыть телеграм и найти там BotFather - бот для создания других ботов
- Создать бота (выбрать имя, адрес и т.д)
- Получить API ключ для бота
- Вставить свой API ключ в файл SRC/Bot/core/settings.py
- Запустить модуль main.py
License ORCP is licensed under the MIT License - see the LICENSE file for details.