#ИИ и автономностьОбъясняем

Дрон сам находит мусор: как это сделали в Познани

Как в Познани научили дрон с нейросетью находить мусор и ставить его на карту: датасет UAVVaste, железо, скорость моделей и код на Python.

Снимки с дрона: нейросеть обвела найденный мусор на дорожке, траве и брусчатке
Иллюстрация: Marek Kraft, Mateusz Piechocki, Bartosz Ptak, Krzysztof Walas, CC BY 4.0, Remote Sensing, 2021

Это перевод с сокращениями научной статьи Marek Kraft, Mateusz Piechocki, Bartosz Ptak, Krzysztof Walas «Autonomous, Onboard Vision-Based Trash and Litter Detection in Low Altitude Aerial Images Collected by an Unmanned Aerial Vehicle» (Remote Sensing, 2021, 13, 965). Статья и иллюстрации распространяются по лицензии CC BY 4.0. Текст переведён и сокращён, код на Python и расчёты по датасету добавила редакция.

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

Снимки с дрона с найденным нейросетью мусором
Рис. 7 из статьи: что нашла нейросеть YOLOv4 на снимках UAVVaste · Иллюстрация: Marek Kraft, Mateusz Piechocki, Bartosz Ptak, Krzysztof Walas, CC BY 4.0, Remote Sensing, 2021

Зачем искать мусор с дрона

Мусор привлекает мусор: люди охотнее бросают отходы туда, где уже грязно, а в чистом месте мусорят реже. Убирают его почти всегда вручную, и чтобы прочесать большой парк или берег, нужно много людей и времени. Дрон с камерой видит территорию сверху и быстро её облетает. Если он сам отметит, где лежит мусор, уборщикам останется пройти по точкам.

Сложность в том, что мусор на снимке сверху очень мелкий. Обычные наборы снимков для обучения нейросетей (COCO, TACO) сняты с уровня глаз, и объекты на них крупные. На снимках с дрона банка или пакет занимает несколько десятков пикселей среди травы, камней и плитки.

Датасет UAVVaste

Для обучения авторы собрали свой набор: 772 снимка с дрона и 3 716 размеченных объектов на улицах, в парках и на газонах (в текущей версии на GitHub 3 718 объектов). Для каждого объекта есть рамка и маска в формате COCO. Набор и сама статья выложены по лицензии CC BY 4.0: GitHub, Zenodo.

Примеры снимков из датасета UAVVaste с отмеченным мусором
Рис. 2 из статьи: снимки из UAVVaste, мусор выделен. Фон меняется от плитки до травы, объекты мелкие · Иллюстрация: Marek Kraft, Mateusz Piechocki, Bartosz Ptak, Krzysztof Walas, CC BY 4.0, Remote Sensing, 2021

Насколько мелкие объекты, мы посчитали сами по файлу разметки (annotations.json из репозитория, 2,7 МБ). Для запуска хватит стандартного Python, сами снимки качать не нужно:

import json
from collections import Counter
from statistics import median

with open("annotations.json") as f:
    coco = json.load(f)

images = {img["id"]: img for img in coco["images"]}
anns = coco["annotations"]
print(f"снимков: {len(images)}, объектов: {len(anns)}")

sizes = Counter(f'{img["width"]}×{img["height"]}' for img in images.values())
print("разрешения:", ", ".join(f"{k} — {v}" for k, v in sizes.most_common()))

per_image = Counter(a["image_id"] for a in anns)
print(f"объектов на снимок: медиана {median(per_image.values())}, максимум {max(per_image.values())}")

# Доля кадра, которую занимает объект (по площади рамки), в процентах
share = [a["bbox"][2] * a["bbox"][3] / (images[a["image_id"]]["width"] * images[a["image_id"]]["height"]) * 100 for a in anns]
print(f"рамка объекта: медиана {median(share):.3f} % кадра")

# Сколько пикселей останется у объекта, если сжать кадр до 608×608, как в статье
def side_608(a):
    img = images[a["image_id"]]
    return max(a["bbox"][2] * 608 / img["width"], a["bbox"][3] * 608 / img["height"])

side = [side_608(a) for a in anns]
small = sum(s < 32 for s in side) / len(side) * 100
print(f"на входе 608 px: медиана длинной стороны {median(side):.0f} px, меньше 32 px — {small:.0f} % объектов")

Результат:

снимков: 772, объектов: 3718
разрешения: 3840×2160 — 384, 3668×1628 — 338, 4000×3000 — 38, 4032×3024 — 4, 960×1280 — 4, 1280×960 — 2, 4056×3040 — 2
объектов на снимок: медиана 4.0, максимум 65
рамка объекта: медиана 0.072 % кадра
на входе 608 px: медиана длинной стороны 22 px, меньше 32 px — 74 % объектов

Медианная рамка занимает 0,07 % кадра. Когда снимок 4K сжимают до 608 × 608 точек, у трёх объектов из четырёх длинная сторона становится меньше 32 пикселей. По классификации COCO это «маленькие объекты», самые трудные для нейросети.

Как устроен дрон

Летает дрон на автопилоте Pixhawk 2 с GPS-модулем Here2, в котором есть компас и барометр для измерения высоты. Маршрут патрулирования задаётся точками, это штатная функция автопилота. Камера на подвесе смотрит строго вниз. Снимки обрабатывает отдельный бортовой компьютер (компаньон-компьютер), который можно заменить, не трогая остальное.

Дрон-сборка: Nvidia Xavier NX, автопилот Pixhawk 2 и GPS-модуль Here2
Рис. 4 из статьи: Nvidia Xavier NX, автопилот Pixhawk 2 и GPS-модуль Here2 с высотомером · Иллюстрация: Marek Kraft, Mateusz Piechocki, Bartosz Ptak, Krzysztof Walas, CC BY 4.0, Remote Sensing, 2021

Авторы проверили три варианта бортового компьютера:

Плата Что это Цена и энергопотребление
Nvidia Jetson Xavier NX модуль с 6-ядерным ARM-процессором и видеоядром на 384 ядра CUDA, 8 ГБ памяти дороже всех, зато запускает любые модели
Raspberry Pi 4 + Google Coral USB ускоритель Edge TPU на 4 TOPS, работает только с моделями, сконвертированными под него дёшево и экономно
Raspberry Pi 4 + Intel Neural Compute Stick 2 ускоритель Myriad X, модели через OpenVINO дёшево, запускает и YOLO, но медленно

Какие нейросети сравнивали

Модели брали готовые, предобученные на COCO, и дообучали на UAVVaste (перенос обучения). Размеры «якорных» рамок YOLO пересчитали под мелкие объекты методом k-средних. Сравнивали YOLOv3 и YOLOv4 с облегчёнными tiny-версиями, YOLOv4-CSP, EfficientDet-d1 и d3, а также SSD с MobileNetV2.

Главная метрика — mAP@50: доля правильно найденных объектов, если рамка совпадает с разметкой хотя бы наполовину. Для задачи «найти и поставить точку на карте» такой точности хватает.

Модель mAP@50 (FP32) mAP@50 (FP16) mAP@50 (INT8)
YOLOv4 0,785 0,784 0,166
EfficientDet-d3 0,751 0,750 —
YOLOv4-CSP 0,736 0,745 —
YOLOv3 0,694 0,694 0,075
EfficientDet-d1 0,669 0,669 —
YOLOv4-tiny-3l 0,615 0,614 —
YOLOv4-tiny 0,566 0,566 0,270
SSD MobileNetV2 0,545 — 0,000
YOLOv3-tiny 0,239 0,232 0,000

Прочерк — модель не удалось собрать в этом формате или его не проверяли.

Лучше всех нашла мусор полная YOLOv4. EfficientDet-d3 чуть хуже по главной метрике, но пропускает меньше объектов, зато даёт больше ложных срабатываний. Интересно, что YOLOv4-CSP, которая на COCO обгоняет обычную YOLOv4, здесь оказалась хуже. Авторы делают вывод: рейтинг моделей на COCO не переносится автоматически на другую задачу.

Перевод модели в половинную точность (FP16) точность почти не меняет. А простое квантование в 8-битные целые (INT8) её обрушивает, у некоторых моделей до нуля. Без специальной подготовки модели INT8 не годится.

Скорость на борту

На Jetson Xavier NX (видеоядро, оптимизация TensorRT), кадров в секунду:

Модель FP32 FP16 INT8
YOLOv4 5,4 19,3 34,7
YOLOv4-CSP 6,4 23,3 —
YOLOv4-tiny 44,9 132,2 176,0
EfficientDet-d1 8,7 16,4 —
EfficientDet-d3 2,8 5,5 —

На ускорителях для Raspberry Pi 4:

  • Google Coral запускает только SSD MobileNetV2: 23,9 кадра в секунду по USB 3.0 и 31,7 в форсированном режиме, которому нужен дополнительный обдув. По USB 2.0 вдвое медленнее.
  • Intel NCS2 крутит полную YOLOv4 примерно с 1 кадром в секунду, YOLOv4-tiny — 11,2 кадра.
  • Голый процессор Raspberry Pi 4 без ускорителя тянет SSD на 1,2 кадра в секунду, а YOLOv4 на 0,07 кадра, то есть один кадр за 14 секунд.

Вывод авторов: лучший вариант — Xavier NX с YOLOv4 в FP16, он даёт почти реальное время при хорошей точности и оставляет запас на будущее. Если важнее цена и энергопотребление, подойдёт Raspberry Pi с USB-ускорителем, но придётся смириться с потерей точности. С 2021 года вышли новые версии YOLO и платы Jetson Orin, но выводы о мелких объектах и квантовании от этого не устарели.

Как найденный мусор попадает на карту

Нейросеть выдаёт рамку в пикселях, а уборщику нужны координаты. Авторы считают их так. Камеру заранее калибруют по шахматной доске (библиотека Kalibr), чтобы убрать искажения объектива. Затем, зная углы обзора камеры и высоту дрона, вычисляют, сколько метров земли помещается в кадр, переводят смещение рамки от центра кадра в метры, поворачивают его на курс дрона по компасу и прибавляют к координатам GPS.

Схема: камера дрона, видимый участок земли и смещение объекта от центра кадра
Рис. 6 из статьи: H — высота, α и β — углы обзора, X и Y — размер видимого участка, DX и DY — смещение объекта · Иллюстрация: Marek Kraft, Mateusz Piechocki, Bartosz Ptak, Krzysztof Walas, CC BY 4.0, Remote Sensing, 2021

Вот эти формулы (1)–(3) из статьи в виде функции на Python. Мы добавили поворот на курс и перевод метров в градусы:

import math

EARTH_R = 6_378_137  # радиус Земли, м (WGS 84)

def litter_position(lat, lon, alt, yaw, px, py, w, h, fov_h, fov_v):
    """Координаты мусора по рамке на снимке.

    lat, lon — координаты дрона; alt — высота над землёй, м; yaw — курс, градусы от севера по часовой;
    px, py — центр рамки, пиксели; w, h — размер кадра; fov_h, fov_v — углы обзора камеры, градусы.
    Камера смотрит строго вниз, верх кадра — по курсу дрона.
    """
    # Формула (1) статьи: сколько метров земли помещается в кадр
    X = 2 * alt * math.tan(math.radians(fov_h / 2))
    Y = 2 * alt * math.tan(math.radians(fov_v / 2))
    # Формулы (2)–(3): смещение рамки от центра кадра в метрах
    right = (px - w / 2) / w * X
    forward = (h / 2 - py) / h * Y
    # Поворот на курс: из «вперёд/вправо» в «север/восток»
    psi = math.radians(yaw)
    north = forward * math.cos(psi) - right * math.sin(psi)
    east = forward * math.sin(psi) + right * math.cos(psi)
    # Метры в градусы
    lat2 = lat + math.degrees(north / EARTH_R)
    lon2 = lon + math.degrees(east / (EARTH_R * math.cos(math.radians(lat))))
    return lat2, lon2, X, Y

# Кадр 8 × 6 м, как в примере авторов: высота 5 м, углы обзора 77,3° и 61,9°
lat, lon, X, Y = litter_position(52.4064, 16.9252, alt=5, yaw=0,
                                 px=3840, py=1080, w=3840, h=2160, fov_h=77.3, fov_v=61.9)
print(f"кадр {X:.1f} × {Y:.1f} м, мусор у правого края: {lat:.6f}, {lon:.6f}")
кадр 8.0 × 6.0 м, мусор у правого края: 52.406400, 16.925259

Мы проверили функцию на трёх случаях. Объект в центре кадра получает координаты дрона. Объект у правого края при курсе на север оказывается в 4 м к востоку. При курсе на восток тот же объект оказывается в 4 м к югу.

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

Сколько успеет облететь дрон

Авторы прикидывают так: если один снимок покрывает участок 8 × 6 м, а дрон летит со скоростью 10 м/с, достаточно обрабатывать около 1,5 кадра в секунду с небольшим перекрытием. За 30 минут дрон просмотрит больше 0,1 км². Проверим:

frame_along, frame_across = 8, 6  # кадр 8 × 6 м, длинная сторона вдоль полёта
speed = 10                        # м/с
overlap = 0.2                     # 20 % перекрытия соседних кадров
minutes = 30

fps = speed / (frame_along * (1 - overlap))
area = speed * minutes * 60 * frame_across / 1e6
print(f"нужно кадров в секунду: {fps:.2f}")
print(f"за {minutes} мин дрон просмотрит {area:.3f} км² ({area * 100:.1f} га)")
нужно кадров в секунду: 1.56
за 30 мин дрон просмотрит 0.108 км² (10.8 га)

Цифры авторов сходятся. Даже YOLOv4 в полной точности на Xavier NX (5,4 кадра в секунду) успевает с запасом. Запас пригодится: снимок высокого разрешения лучше резать на части и проверять каждую отдельно, тогда мелкие объекты не теряются при сжатии.

Что дальше и о чём предупреждают авторы

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

Авторы планируют расширить датасет, добавить синтетические снимки (вклеивать мусор в фоны, снятые с дрона) и связать систему с сервисом OpenLitterMap, где люди отмечают мусор на карте.

Отдельно авторы пишут о приватности. Съёмка с такой детализацией, чтобы видеть банку на газоне, может восприниматься как слежка. Их система переводит снимки сразу в точки на карте, но перед запуском всё равно нужны меры безопасности, в том числе аудит программ: главными угрозами для дронов авторы называют перехват канала связи и взлом программ. В России к этому добавляются правила полётов: над населёнными пунктами нужно разрешение на использование воздушного пространства, а во многих регионах полёты сейчас запрещены. Подробнее в статье «Где можно летать на квадрокоптере».

Как повторить

  1. Скачать UAVVaste с GitHub (разметка) или целиком с Zenodo (архив со снимками около 3 ГБ).
  2. Дообучить на нём детектор, предобученный на COCO.
  3. Запустить модель на компаньон-компьютере рядом с полётным контроллером, камеру направить вниз.
  4. Каждую рамку переводить в координаты функцией выше, используя высоту, курс и координаты из автопилота.

Что такое компьютерное зрение и где ещё его применяют на дронах, рассказано в словаре. Сами снимки для такого проекта можно сделать и с обычного дрона в ручном полёте, а обработать потом на компьютере: так проще начать.

Источники

Частые вопросы

Можно ли повторить такую систему самому?

Да, авторы собрали её из готовых деталей: автопилот Pixhawk, GPS-модуль, камера смотрит вниз, а нейросеть работает на Jetson Xavier NX или Raspberry Pi с USB-ускорителем. Датасет UAVVaste открыт, на нём можно обучить свою модель. Сложнее всего разрешение на полёты над городом.

Почему мусор на снимках с дрона искать труднее, чем на обычных фото?

Он очень мелкий. В UAVVaste рамка вокруг мусора занимает в среднем 0,07 % кадра, а после сжатия снимка до 608 × 608 точек у трёх объектов из четырёх длинная сторона меньше 32 пикселей. Модели, обученные на фото с уровня глаз, такие объекты почти не видят.

Сколько площади дрон проверяет за полёт?

По расчёту авторов, при кадре 8 × 6 м и скорости 10 м/с нужно обрабатывать около 1,5 кадра в секунду, и за 30 минут дрон просматривает больше 0,1 км², это около 11 гектаров.

Термины в статье

Читайте также