Остановимся на скелетных(структурных) методах, которые используют для обработки изображений информацию о топологии объекта. Ключевое понятие структурных методов - контур.
Контур - это внешние очертания (обвод) предмета или объекта. При проведении контурного анализа полагается, что контур содержит достаточную информацию о форме объекта, внутренние точки объекта во внимание не принимаются. Вышеприведённые положения, разумеется, накладывают существенные ограничения на область применения контурного анализа, которые, в основном, связаны с проблемами выделения контура на изображениях: из-за одинаковой яркости с фоном объект может не иметь чёткой границы, или может быть зашумлён помехами, что приводит к невозможности выделения контура; перекрытие объектов или их группировка приводит к тому, что контур выделяется неправильно и не соответствует границе.
Однако, переход к рассмотрению только контуров объектов позволяет уйти от пространства изображения к пространству контуров, что существенно снижает сложность алгоритмов и вычислений. Резюмируя, контурный анализ имеет довольно слабую устойчивость к помехам, и любое пересечение или лишь частичная видимость объекта приводит либо к невозможности детектирования, либо к ложным срабатываниям, но простота и быстродействие контурного анализа, позволяют вполне успешно применять данный подход (при чётко выраженном объекте на контрастном фоне и отсутствии помех).
После выделения контура в бинарный вид, он
подвергается процедуре скелетизации (утоньшению). Каждый последовательный
контур скелетного представления описывается в виде последовательного набора
особых точек и так называемого цепного кода, состоящего из точки привязки,
числа кодов и массива направлений из очередной точки на следующую точку. Особые
точки - это концевые точки и точки ветвления (триоды), т.е. точки, соседи
которых образуют не менее трех связных областей. На рис. 12 изображен образ,
обладающий двумя внутренними контурами, одной концевой точкой и тремя триодами
[8].
Рис. 12. Образ, прошедший процедуру скелетизации
В полученном описании производится огрубляющая
предобработка, состоящая в удалении коротких линий, объединении близких
триодов, уничтожении малых внутренних контуров. Для внешнего контура находится
его тип или топологический код. Для этого контур записывается в виде
последовательного набора номеров особых точек, соответствующих обходу по
часовой стрелке. Затем с помощью пере нумерации делается попытка отождествления
контура с одним из основных типов[6].
. БиблиотекаOpenCV
В данном разделе представлены данные о
библиотеке OpenCV - основного инструмента для разработки проекта. OpenCV - это
одна из библиотек для работы с компьютерным зрением (библиотекой в
программировании называется сборник подпрограмм или объектов, используемых для
разработки программного обеспечения). OpenCV реализована на C/C++, также
разрабатывается для Python, Java, Ruby, Matlab, Lua и других языков. Может
свободно использоваться в академических и коммерческих целях - распространяется
в условиях лицензии BSD. Библиотека довольно популярна, на текущий момент имеет
более 5 миллионов скачиваний и недавно была предложена в качестве основы для стандарта
Khronos по компьютерному зрению. Примечательно, что OpenCV был разработан
программистами из российского отделения компании Intel.
3.1 Примитивные типы данных в OpenCV
включает в себя множество примитивных типов данных. Эти данные не являются примитивными с точки зрения языков программирования высокого уровня, но являются самыми элементарными с точки зрения OpenCV. [5]
Самый простой тип данных - Point. Эта простая
структура состоит только из двух полей x и y типа int. Point2D32f содержит два
поля x и y типа float. Point3D32f содержит три поля x, y и z типа float.
Используется для задания и обработки графических точек.содержит два поля width
и height типа int. Size2D32f содержит два поля width и height типа float. Size
содержит в себе информацию о размере того или иного массива.содержит четыре
поля x, y, width и height типа int и представляет собой прямоугольник.содержит
четыре переменные типа double. На самом деле Scalar включает в себя одно поле
val, которое является указателем на массив, содержащий четыре числа типа
double. Scalar хранит в себе данные о цвете того или иного объекта и, в отличие
от всех остальных структур содержит три конструктора. Первый может принимать
один, два, три или четыре аргумента и присваивать их соответствующим элементам val
[]. Второй конструктор, RealScalar, принимает один аргумент и устанавливает
соответствующее значение val [0], остальные элементы устанавливаются в 0.
Третий конструктор ScalarAll так же принимает один аргумент и инициализирует
все элементы val [] этим значением., Size, Rect и Scalar чрезвычайно полезны,
потому что существенно упрощают код. Они позволяют перейти от объектов,
привычных в численных вычислениях к объектам, необходимым для работы с
изображениями.
3.2 Классы библиотеки OpenCV
В данном подразделе обозначим основные классы библиотеки OpenCV, причем функционал тех, которые будут широко использованы в практической части, обговорим подробнее.-основная функциональность. Включает в себя базовые структуры, вычисления (математические функции, генераторы случайных чисел) и линейную алгебру, DFT, DCT, ввод/вывод для XML и YAML и т. д.- работа с матрицами (многомерными массивами). Понятие матрицы в OpenCV несколько более абстрактно, нежели в линейной алгебре. В частности, элементы матрицы не обязательно должны быть просто числами, а могут представлять собой любые объекты, в том числе и сторонних библиотек.- обработка изображений (фильтрация, геометрические преобразования, преобразование цветовых пространств и т. д.). Imgproc это базовая структура, используемая для кодирования того, что мы называем "изображение". Эти изображения могут быть чёрно-белыми, цветными, 4-х канальными (RGB+Alpha), и каждый канал может содержать либо целые, либо вещественные значения. Следовательно, этот тип является более общим, чем стандартные 3-х канальные 8-битные изображения. OpenCV располагает обширным арсеналом операторов для работы с этими изображениями, которые позволяют изменять размеры изображений, извлекать отдельные каналы, складывать два изображения, и т.д. В сущности, это объект Mat, но с некоторыми дополнениями для интерпретации матрицы как изображения. Одно важное отличие Imgproc от Mat заключается в поведении imageData. Данные Mat являются объединением, поэтому существует возможность задать тип указателя. Указатель imageData задается жестко как uchar*. При работе с матрицами, необходимо уменьшать смещение, так как указатель данных не всегда может быть типа byte, в то время, как указатель данных изображения всегда типа byte, смещение можно использовать "как есть".
HighGUI - простой UI, ввод/вывод изображений и видео. Функции OpenCV, которые позволяют взаимодействовать с операционной системой, файловой системой и аппаратными средствами, такими, как камера, собраны в библиотеке HighGUI (что означает "высокоуровневый графический пользовательский интерфейс"). HighGUI позволяет открывать окна для отображения изображений, читать и записывать графические файлы (изображения и видео), обрабатывать простые события мыши, указателя и клавиатуры. Данный класс также позволяет создавать такие полезные элементы, как ползунок. HighGUI имеет достаточный функционал для разработки различного рода приложений. При этом наибольшая польза от использования данной библиотеки в её кроссплатформенности. библиотека HighGUI состоит из трех частей: аппаратной, файловой и GUI. Аппаратная часть в первую очередь касается работы с камерой. HighGUI предоставляет простые механизмы подключения и последующего получения изображения с камеры. Все, что касается файловой системы, в первую очередь связано с загрузкой и сохранением изображения. Приятной особенностью библиотеки является наличие методов, которые одинаково обрабатывают видеопоток и из файла, и с камеры. Та же идея заложена и в методы обработки изображений. Функции просто полагаются на расширения файлов и автоматически обрабатывают все операции по кодированию и декодированию изображений. Третья часть HighGUI - GUI. Библиотека предоставляет несколько простых функций, которые позволяют открывать окно и отображать в нем изображения. Тут же (в окне) существует возможность обрабатывать события, поступившие от мыши и клавиатуры [10].
ML - модели машинного обучения (SVM, деревья решений, обучение со стимулированием и т. д.).
Features2d - распознавание и описание плоских примитивов (SURF, FAST и другие, включая специализированный фреймворк).
Video - анализ движения и отслеживание объектов (оптический поток, шаблоны движения, устранение фона).
Objdetect - обнаружение объектов на изображении (нахождение лиц с помощью алгоритма Виолы-Джонса, распознавание людей HOG и т. д.).
Calib3d - калибровка
камеры, поиск стерео-соответствия и элементы обработки трёхмерных данных.
4. Разработка системы
управления квадрокоптером на базе IMUи
ультразвукового дальномера HC-504
Описанный в работе проект возник в результате
идеи создания нового метода управления беспилотными дронами. Самый
распространенный на сегодняшний день способ управления - пульт с несколькими
джойстиками и тумблерами, передающий все каналы управления на бортовой
контроллер. И хотя квадрокоптер имеет способность самостоятельно
стабилизироваться в воздухе, управление им - нетривиальная задача, которая
требует многих часов практики. Идея проекта состоит в том, чтобы перенести все
элементы управления на интуитивно понятный базис - жесты одной руки. Как было
сказано выше, основные каналы управления носят названия газ, рыскание, тангаж и
крен. Также в полетном контроллере Ardupilot несколько каналов выделено под
изменение режимов непосредственно в процессе полета. В данной работе
остановимся над контролем шестью каналами управления.
Рис. 13. Принципиальная схема устройства
Принципиальная схема устройства показана на рисунке. Ее ключевая часть - микроконтроллер AVRна базе платформы Arduino. На него приходят сигналы с датчиков, обрабатываются и с помощью радиомодулей отправляются на борт. Каналом газа управляет ультразвуковой дальномер - чем больше расстояние от него до руки, тем больше мощности подается на двигатели. За рыскание, тангаж и крен отвечает так называемое инерционное измерительное устройство (IMU), закрепленное на руке, - гироскоп, акселерометр, компас и барометр, собранные в одной плате. В определенном для каждого угла Эйлера интервале борт будет копировать положение устройства.
Наконец, каналы, предназначенные для изменения режимов управляются с помощью технологий компьютерного зрения. Камера захватывает сигнал с изображением жестов руки и затем они анализируются в программе, написанной на языке Java. Этот язык выбран по причине его мультиплатформерности для последующего переноса программы на более портативное устройство, чем стационарный ПК или ноутбук.
Начнем сборку устройства с манипулятора, который
будет управлять первыми четырьмя каналами. В качестве логического процессора
будет использоваться микроконтроллер AtmelATMega2560 на базе Arduino.
Использование Arduino позволяет упростить разработку и отладку устройства, в
дальнейшем от него можно отказаться, ограничиваясь только микроконтроллером.
4.1 Сборка устройства и код для
получения данных
Как было сказано выше, беспилотный дрон управляется четырьмя основными каналами - газ, рыскание, крен и тангаж. Полетный контроллер принимает на своих входах значения каждого канала как целое число размером 1 байт (от 0 до 255 для газа и от -127 до 127 для рыскания, крена и тангажа). Значит первая цель - получить эти значения как переменные в микроконтроллере. В скетче можно сразу объявить эти переменные и назвать их throttle, yaw, pitch и roll. В этих переменных будут хранится необработанные показатели датчиков. Для данных, прошедших обработку и готовых к отправке, объявим еще четыре переменных: sendThrottle, sendYaw, sendPitch, sendRoll.
Для получения значения газа будет использоваться ультразвуковой дальномер HC-SR04. Необходимо подключить его к выводам 5V и GND для обеспечения питания и два логических вывода соединить с любыми цифровыми выводами Arduino. Подсоединим вывод trig к цифровому выводу с номером 8 и определим его в программе как TRIGGER_PIN, а echo - к выводу 9 и определим, как ECHO_PIN. Для работы с дальномером будет использоваться библиотека NewPing.h. После ее импортирования следует ввести команду NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE), где MAX_DISTANCEустановим как 200 - это максимальное измеряемое значение в сантиметрах. Эта команда создает объект sonar, методами которого можно получить расстояние, измеряемое дальномером. Теперь в функции loop можно присвоить переменной throttle значение sonar.ping и ее значение будет пропорционально расстоянию до препятствия. В этом можно убедиться, если вывести значение переменной в монитор серийного порта. В конце функции loop также необходимо ввести задержку в 5мс для того чтобы периоды опроса не «наслаивались» друг на друга и не возникало ошибочных значений.
В массиве представленных значений присутствует достаточно сильный шум, который может негативно повлиять на результаты их анализа. Необходимо включить в программу фильтрацию для переменной throttle. Имеет смысл в данной работе использовать упрощенный фильтр Калмана. Принцип его работы приведен выше. Функция фильтра принимает два аргумента - стандартное отклонение величины от математического ожидания и скорость реакции на изменение. Первый аргумент считается опытным путем - для этого нужно создать массив данных достаточного размера на выходе датчика без изменения внешних условий, а затем найти стандартное отклонение по генеральной совокупности. Можно модифицировать программу для выполнения этого действия, но удобнее выполнить его в программе MicrosoftExcel с помощью функции СТАНДОТКЛОН.Г. Из выборки около 750 элементов получаем стандартное отклонение 21,47. Запишем это значение при объявлении констант в начале кода. Подбор скорости реакции на изменение производится вручную, эмпирическим путем. Нужно выставить значение достаточно малое, чтобы дрон быстро воспринимал команду изменения газа и достаточно большую, чтобы отфильтровать лишние значения. Для тестирования добавим в программу функцию с алгоритмом упрощенного фильтра Калмана, которая принимает значение и возвращает его отфильтрованным. Сразу после получения переменной throttle в функции loop вызовем фильтрующую функцию, в качестве аргумента которой будет значение throttle и значение которой будет снова присваиваться переменной throttle. Далее эмпирическим путем определено, что оптимальный коэффициент для данной задачи - это число 0,02.
Теперь произведем аналогичные действия для остальных трех каналов, а именно считаем и отфильтруем данные с датчиков. Показания рыскания, крена и тангажа будут считываться с инерционного измерительного устройства, который имеет в составе гироскоп, акселерометр, барометр и компас. Оно так же нуждается в питании с напряжением 5В и имеет два логических выхода. Передача данных осуществляется по протоколу I2C, который поддерживается Arduino, поэтому для передачи большого количества данных достаточно двух проводов. Подсоединим устройство к I2C-совместимым портам ArduinoMega, а именно 20 и 21. Они помечены метками SDA и SCL.
Для работы с инерционным измерительным устройством необходимо импортировать в скетч две библиотеки - Wire.h для работы с протоколом I2C и TroykaIMU.h для работы с самим устройством. Библиотека написана по принципам объектно-ориентированного программирования, поэтому для дальнейшей работы, вне функций необходимо создать по объекту для каждого использованного модуля, а именно объекты классов Accelerometer, Gyroscope и Compass. Все полученные величины будут проходить через фильтр Магвика, поэтому для него тоже создать объект класса Magwick. Дадим ему имя filter, а объектам для акселерометра, гироскопа и компаса - accel, gyro и compass соответсвенно.