Автономная езда по тротуару посредством OpenCV и Tensorflow

    Создание автономных машин — популярная нынче тема и много интересного тут происходит на любительском уровне.

    Самым старым и известным курсом была онлайн-степень от Udacity.

    Итак, в автономных машинах есть очень модный подход — Behavioral Cloning, суть которого заключается в том, что компьютер учится вести себя как человек (за рулем), опираясь только на записанные входные и выходные данные. Грубо говоря, есть база картинок с камеры и соотвествующий им угол поворота руля.

    В теории, обучив на этих данных нейросеть, мы можем дать ей порулить машиной.
    Этот подход базируется на статье от Nvidia.

    Существует множество реализаций, сделанных в основном студентами Udacity:


    Еще более интересно применение в реальных проектах. Например, машинка Donkey Car управляется специально обученной нейросетью.

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

    Итак, что такое тротуар с точки зрения компьютера?

    Некоторая область на картинке, которая отличается цветом от других областей.

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

    (Под наиболее серым имеется в виду минимальная разница между значениями RGB). Это свойство серого и будет ключевым при распознавании тротуара.

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

    tank in a park

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

    • взять среднюю яркость (в формате HSV)
    • или средний RGB кусочка, гарантированно состоящего из дороги (в таком случае это будет левый нижний угол).

    Установив такие критерии распознавания тротуара, пробегаем по картинке и получаем какое-никакое очертание дороги.


    Следующим шагом надо превратить аляповатое пятно в действия — ехать прямо или повернуть направо или налево.

    Прямо мы едем, если правая кромка видна и угол меньше 45 градусов от вертикали.

    Налево поворачиваем, если правая кромка видна и угол отклоняется от вертикали вниз.
    Направо поворачиваем, если не видим правой кромки.

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

    Вот тут то и приходят на помощь нейросети.

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

    Эти маски раскладываем на 3 кучки — Left, Right, Straight и обучаем на них классификатор нейросети.

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

    Вот образцы масок:

    Налево:


    Направо:


    Прямо:


    Для работы с нейросетью я использовал Keras + Tensorflow.

    Поначалу была идея взять структуру нейросети от Nvidia, но, она очевидно, предназначена для несколько других задач и с классификацией справляется не очень. В итоге оказалось, что простейшая нейросеть из любого туториала про multi-category classification дает вполне приемлемые результаты.

    model = Sequential()
    activation = "relu"
    
    model.add(Conv2D(20, 5, padding="same", input_shape=input_shape))
    model.add(Activation(activation))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
    
    model.add(Conv2D(50, 5, padding="same"))
    model.add(Activation(activation))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
    
    model.add(Flatten())
    model.add(Dense(500))
    model.add(Activation(activation))
    
    model.add(Dense(cls_n))
    opt = SGD(lr=0.01)
    model.add(Activation("softmax"))
    model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
    

    Обучив первую версию сети, я уперся в ее несовместимость с Raspberry Pi. До этого я использовал Tensorflow версии 1.1, с помощью шаманства собранную одним очень умным человеком.

    К сожалению, эта версия устарела и не могла читать модели из Keras.

    Однако недавно люди из Гугла наконец-то снизошли и собрали TF под Raspberry Pi, правда под новую версию Raspbian — Stretch. Stretch был всем хорош, но год назад у меня под него не собрался OpenCV, поэтому танк ездил на Jessie.

    Теперь же под давлением перемен пришлось переходить на Stretch. Tensorflow встал без проблем (хоть и заняло это несколько часов). OpenCV за год тоже не стоял на месте и уже вышла версия 4.0. Вот ее и удалось собрать под Stretch, так что препятствий для миграции уже не осталось.

    Были сомнения, как Raspberry потянет в реалтайме такого монстра как Tensorflow, но все оказалось в целом приемлемо — несмотря на начальную загрузку сети порядка нескольких секунд, сама классификация способна отрабатывать несколько раз в секунду без значительного отжора памяти и CPU.

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

    С обновленной прошивкой танк рассекает по парку.

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


    Можно теперь его выгуливать по утрам и детектировать встречных собак.

    Ссылки:

    Поделиться публикацией

    Комментарии 22

      0

      Не очень понятно мне вот это:


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

      В сочетании с вот этим:


      Итак, в автономных машинах есть очень модный подход — Behavioral Cloning, суть которого заключается в том, что компьютер учится вести себя как человек (за рулем), опираясь только на записанные входные и выходные данные. Грубо говоря, есть база картинок с камеры и соотвествующий им угол поворота руля. В теории, обучив на этих данных нейросеть, мы можем дать ей порулить машиной.

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

        0
        Да, в результате разъездов генерятся тысячи картинок. Далеко не все из них пригодны.
        Надо проверить как на них распознается дорога. И разложить их по категориям — право, лево, прямо. На все это очень много времени уходит.
          0

          Т.е. это ручной труд?

            0
            В основном да, к сожалению.
              0

              Не пробовали оценить насколько данный подход по времени был выгоден/невыгоден по сравнению с алгоритмическим подходом к решению данной задачи?

                0
                Все упирается в задачу распознавания дороги, она технически гораздо сложнее, чем принятие решений на основе нейросети и зависит от условий.
                Т.е чтобы подготовить данные для нейросети, нужно сначала подобрать параметры распознавания дороги для данной местности и уровня освещенности.
                  0
                  Все упирается в задачу распознавания дороги, она технически гораздо сложнее,

                  ОК, но разве эта задача уже не решена другими? Я имею ввиду, что нельзя взять какую-то готовую распознавалку, которая уже обучена распознавать дорогу, подцепить к вашей камере на ровере и получить результат?
                  Я видел десятки человек, натаскивающие нейросети именно на это — выделяющие маркерами дороги, обочины, автомобили. Разве результат их работы закрыт/недоступен?

                    0
                    В прямо готовом виде я не встречал пока. Может быть плохо искал.
                    Вот это — «выделяющие маркерами дороги, обочины, автомобили» — как правило учебные задания, выделяющие части картинки по цвету.
                    В учебных картинках все получается хорошо, в реальной жизни не так гладко.
                    Мне приходило в голову попробовать выделить дорогу посредством сегментирования, но это тема для отдельной статьи.
                      0
                      Вот это — «выделяющие маркерами дороги, обочины, автомобили» — как правило учебные задания, выделяющие части картинки по цвету.

                      Да нет, они работали на автомобильные фирмы целыми месяцами.


                      Собственно, вы наверное слишком сложную задачу хотели решить — научить вездеход ездить без линий разметки. А в реальности автомобили все же на нее ориентируется.


                      Попробуйте упростить эксперимент — на той же парковой дороге нарисовать маркером или мелом линии разметки, чтобы камера с робота показывала примерно то же самое, что видит обычный автомобиль. А потом применить готовую нейросеть, уже обученную на это. Сработает?

                        0
                        >>Собственно, вы наверное слишком сложную задачу хотели решить
                        да, конечно, по линиям гораздо проще ориентироваться через Computer Vision.
                        Я обучал нейросеть на комнатных данных из
                        предыдущей статьи, она показывала приемлемые результаты на цветных картинках, но на роботе я ее не запускал.
                    0
                    Все упирается в задачу распознавания дороги, она технически гораздо сложнее, чем принятие решений на основе нейросети и зависит от условий.

                    На самом деле, нет.
                    Если у вас была приличная база неразмеченных картинок, то разметить пару десятков кадров, а потом обучить Unet с псевдолейблингом до приемлемой точности — это решаемая задача.
                      0
                      Я пробовал скармливать в нейросеть цветные картинки (уменьшенные и размытые), но она не ловила закономерности.
                      Бегло почитал статью про Unet, сложилось впечатление что под сегментацией они понимают то, что в OpenCV называется нахождением контуров.
                        0
                        Под сегментацией «они» подразумевают то, что называется задачей семантической сегментации.
                        Удивительно, что вы пишете про автономную езду, не зная про стандартные виды задач CV, которые повсеместно используются в этом домене.
                          0
                          Сегментация — очень интересная тема, но для задачи руления она не первостепенна.
                            0
                            Вы не поверите. Self-driving cars — это тот домен, который крайне активно драйвит развитие сегментации (особенно в контексте видео).
                              0
                              Спасибо за информацию, буду смотреть в этом направлении тоже.
          0
          Не пробовали запускать сеть через OpenCV?
            0
            Что вы имеете в виду? Распознать дорогу какой то уже обученной сетью?
              +1
              Предполагаю, речь про поддержку нейросетей в OpenCV.
                0
                Я понимаю. Но какую задачу решать с помощью нейросети в контексте статьи?
                Сама возможность использовать готовую нейросеть в OpenCV конечно есть, в самой первой своей статье я так делал, чтобы детектировать предметы в комнате.
                  0
                  Не устанавливать TensorFlow на Raspberry Pi и, возможно, получить больше кадров в секунду с OpenCV?
                    0
                    Tensorflow может читать сети, обученные в Керасе, а это самый быстрый и простой способ. OpenCV понимает не все форматы и с этим надо разбираться. Я этого не делал, так как проблема производительности пока не стоит на первом месте.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое