Обнаружение препятствий на OpenCV. Часть 2
С момента последней статьи прошел почти год. Спасибо читателям за комментарии, они здорово помогли, отдельная благодарность @Meklonза идею с фильтрами и в целом за участие в дискуссии. Сама эта идея за весь период времени из головы благополучно вылетела, но видимо не совсем. :) Об этом чуть позже.
Произошло немало событий, времени на мое хобби с автономным катером нашлось откровенно мало. :/
Но идея обнаружения абстрактных препятствий не давала мне покоя. Постоянно казалось, что до результата рукой подать.
Аппаратная часть.
Цены уползли вверх и теперь я не могу позволить легкомысленно утопить аппаратуру катера. Как я рассуждал раньше: «Ну что там Raspberry Pi и несколько датчиков. Всегда можно взять новую «малинку», восстановить образ из бэкапа и продолжить испытания.»
Сейчас же ситуация обратная. Если потеряю катер со всей электроникой, то дальше решать задачу, скорее всего, смогу только теоретически, на листочке в клеточку.
Поэтому, я спроектировал и распечатал на 3d принтере новый герметичный корпус с аккумуляторным отсеком.
Герметичный бокс для электронной начинки.
Штатный бокс демонтировал, в него уже ничего не помещается. Заодно обслужил вал гребного винта. Все новые технологические отверстия тщательно загерметизировал.
Начало сборки новой конфигурации катера.
Трудно не заметить — на катере появилась камера на мачте. Этому есть объяснение: чем выше точка обзора, тем раньше мы сможем увидеть препятствие, а значит у нас будет больше времени для принятия решения. Другими словами — мы отодвигаем границу «видимого горизонта».
Картинка из Википедии.
После сборки получаем новую компоновку:
Катер с новой компоновкой.
Но плотная компоновка тут же подкинула проблему с охлаждением. В замкнутом пространстве микрокомпьютер и регулятор оборотов двигателя превращают крышку отсека в утюг.
Чтобы снизить температуру, необходимо повысить производительность водяного охлаждения, оно тут предусмотрено штатно. Проектирую и печатаю новый водозаборник который будет крепиться на дейдвудную трубку вала.
Сравните размеры штатного водозаборника и нового пластикового.
Программная часть — самое простое! …или нет?
Уже потираю руки — аппаратура надежно защищена, алгоритм давно придуман и проверен!
Меня напрягало пользоваться окошком терминала для запуска программы автопилота и контроля параметров беспилотника. А раз добавили камеру — логично набросать веб-интерфейс, чтобы следить за испытаниями в реальном времени.
Слева — было, справа — стало.
Включаем, понеслось…
Это просто ад какой-то!
Абсолютно неожиданно: в воде, в хорошую погоду, могут отражаться облака, деревья или любые другие объекты над водой. А еще, алгоритм поиска граней неплохо обнаруживает рябь и волны на поверхности. Все это накладывается друг на друга и превращается в одно хаотичное пятно. Алгоритм адаптивный, при увеличении числа помех я понижаю порог чувствительности и катер просто перестает видеть материальные препятствия на пути.
Вот тут я знатно подвис, я ставил себе задачу обнаружения препятствий и планировал отправить автономный катер в большое путешествие, но не смог даже отплыть от берега — вся зеркальная поверхность воды превратилась в сплошные препятствия!
Вывод: ничего не получилось! …или нет?
Я продел немалую работу: спроектировал и собрал техничку, провел тюнинг игрушечного катера, допилил ПО и все для того, чтобы столкнуться с фундаментальной проблемой — отражения на воде.
Для алгоритма нет никакой разницы какие данные он получает с камеры, он тем и отличается от интеллекта человека, что ему все равно какой объект находится в воде: пакет или облако, отражение дерева или утонувшее бревно, птица в небе или водоросль в толще воды… Что, напомню, совсем не похоже на заплыв в идеальных условиях:
Так я видел работу автопилота изначально.
Ну не получилось и не получилось, не может отличить и что ж теперь? В лепешку расшибиться?! Зато я весело провел время!
На этом могла бы закончиться статья про Epic Fail в обнаружении препятствий с помощью камеры, если бы я сел ее писать сразу после полученных результатов. Но рука не поднялась. Я просто убрал катер на дальнюю полку и забыл на некоторое время.
Но осознание неудачи не давало покоя, нет-нет, да появлялась мысль:, а вдруг есть другие варианты решения задачи. И когда ощущение фиаско притупилось, я понемногу стал возвращаться к обдумыванию той самой задачи, как же обнаружить (чтоб их!!!) абстрактные препятствия, не прибегая к ресурсоемким нейорсетям.
С чистого листа.
Немного отдохнув, я решил отказаться от идеи искать объекты по граням. Скорее всего для моей задачи это тупик. Нужны были новые идеи и я стал разбираться в различных методах фильтрации изображений. Опыт подсказывал, что задача не решается из-за отсутствия необходимых знаний. Почитав и поразмыслив, в голову пришла идея применить некоторые полезные фильтры, которые могли бы подтолкнуть к правильному решению.
Интуитивно, я понимал, что отражения на воде имеют какие-то особенности, которые могут позволить отфильтровать их из общего окружения.
У меня уже накопилось достаточно видеоматериала с испытаний, чтобы эмпирически попытаться получить удовлетворительный результат.
Во время изысканий, настоящим откровением стал «фильтр Собеля». Метод находит градиент каждого пикселя (или заданной области пикселей). Причем направление градиента можно выбирать. Нашел я его во время опытов и только потом узнал, что он используется как простейший метод нахождения края объекта.
Пример фильтра Собеля из Википедии
В моем случае этот фильтр дает поляризационный эффект. Обратите внимание, что отражение облаков и рябь на воде эффективно отфильтровываются, а небольшой лист на воде светится яркой точкой. Повышаем контрастность и данные с камеры превращаются в подобие радара который «видит» материальные объекты на нашем пути.
Сравнение старого и нового метода обнаружения препятствий:
Данный метод показал хорошие результаты и в более сложных условиях. Там где алгоритм Canny Edges попросту сходит с ума и видит практически непрерывное препятствие, фильтр Собеля успешно отстраивается от большинства помех.
Canny Edges слева, Sobel справа
А как на практике?
На практике остается посчитать весовые коэффициенты для набора возможных траекторий и встроить новый метод в программу пилотирования катера.
Погонял автопилот на других видео и убедился, что алгоритм отлично справляется с нашей задачей.
«Пока суть да дело — лето пролетело.»
Лезть в холодную р.Волгу уже не так охота как при +30°, а значит снова придется ждать лета! Остается надеяться, что сюрпризов больше не будет и я смогу представить вам полный обзор самостоятельного путешествия катера с автопилотом и компьютерным зрением на Raspberry Pi.
Спасибо, что прочитали статью!