Беспилотные мультироторные летательные аппараты — КиберПедия 

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

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

Беспилотные мультироторные летательные аппараты

2022-07-06 19
Беспилотные мультироторные летательные аппараты 0.00 из 5.00 0 оценок
Заказать работу

Содержание

Введение

. Беспилотные мультироторные летательные аппараты

.1 Базовые принципы полета квадрокоптера

.2 ПИД регуляторы

.3 Полетный контроллер

.4 Фильтр Калмана

. Технология компьютерного зрения

.1 Введение в компьютерное зрение

.2 Методы обработки изображений в компьютерном зрении

. Библиотека OpenCV

.1 Примитивные типы данных в OpenCV

.2 Классы библиотеки OpenCV

.Разработка системы управления квадрокоптером на базе IMU и ультразвукового дальномера HC-504

.1 Сборка устройства и код для получения данных

.2 Преобразование данных

. Разработка ПО для распознавания жестов руки с видеосигнала методами библиотеки OpenCV

.1 Постановка задачи и проектирование программного обеспечения

.2 Захват видеосигнала

.3 Обработка изображения

.4 Выделение контуров

.5 Нахождение дефектов обводящего контура

.6 Фильтрация точек дефектов

.7 Обработка результатов

. Формирование сигналов и передача полученных данных

.1 Передача данных через серийный порт

.2 Передача данных на бортовой контроллер

Заключение

Список использованных источников

Приложение


Введение

 

На сегодняшний день беспилотные летательные аппараты (БПЛА) - бурно развивающаяся область техники. БПЛА выполняют широкий спектр как военных, так и гражданских задач. В последние годы большую популярность приобрели мультироторные БПЛА (мультикоптеры) по причине доступности и простоты эксплуатации. Мультикоптеры используются для доставки грузов, фото- и видеосъемки, поисковых работ, наблюдения за природными явленими и многого другого.

Разработки в этой области активно ведутся как коммерческими предприятиями, так и любителями. В данной работе описан проект, цель которого - автоматизировать систему управления мультикоптера с четырьмя роторами, сделать управление интуитивно понятным и отзывчивым. В результате было разработано устройство, способное передавать «с Земли» всю информацию, необходимую для пилотирования мультикоптера, используя лишь жесты одной руки. Разработка устройства от проектирования и до готового кода велась самостоятельно и в ней, кроме всего прочего, были использованы источники с открытым исходным кодом - платформа Arduino ибиблиотека компьютерного зрения OpenCV.Устройство является прототипом, но имеет перспективы к развитию и реальному использованию.

 


 

ПИД регуляторы

 

Сигнал с полетного контроллера поступает не напрямую на двигатель, а на так называемый ПИД-регулятор, который исходя из входного сигнала выдает двигателю соответствующее напряжение. ПИД-регулирование - необходимая технология для управления квадрокоптером.

Например, имеется дрон которому необходимо повернуться на 60 градусов относительно центра масс. Движение вокруг центра осуществляется подачей на его привода требуемой угловой скорости вращения. Для того, чтобы повернуться именно на 60 градусов необходимую угловую скорость надо подавать по определённому закону. В момент, когда разность между текущим углом и требуемым ещё значительна, угловая скорость должна быть высокой. При уменьшении же разности должна уменьшаться и скорость. Когда разность окажется равна 0, угловая скорость также должна равняться 0. Однако, такой закон не представляется возможным определить заранее, потому что квадрокоптер обладает моментом инерции, и он способен просто пролететь необходимое положение, а в этом случае придётся подавать скорость в обратном направлении. Самое стандартное решение в такой ситуации - сообщать необходимую скорость как разность требуемого положения и текущего, умноженную на определённую неотрицательную постоянную. Подобный алгоритм называется П регулятором. Однако, такой алгоритм обладает существенным недостатком: в случае, когда требуемое угловой положение вращается с определённой угловой скоростью, то дрон никогда не догонит эту точку. Рано или поздно наступит момент, когда угловая скорость, выверенная П регулятором, будет равна угловой скорости вращения необходимого положения. Для качественного решения данной задачи рекомендуется сложить скорость от П регулятора со скоростью, рассчитанной как интеграл по времени ошибки по углу, умноженный на определённую неотрицательную постоянную. В такой ситуации необходимая скорость будет тем выше, чем дольше дрон не способен занять требуемое угловое положение. Данный алгоритм является ПИ регулятором. Но и этот алгоритм можно доработать. В момент, когда ошибка по углу будет равняться 0, дрон под действием сил инерции пролетит нужное положение, при условии, что его скорость до этого была относительно высокой. Чтобы этого избежать необходимо совершать торможение чуть быстрее, когда ещё ошибка мала, а именно - к требуемой скорости от ПИ регулятора добавить производную ошибки по времени, которая в свою очередь умножается на положительную постоянную. Это и есть ПИД регулятор.

Пропорционально-интегральное-дифференциальное управление может быть представлено следующей схемой:

 

Рис.3. Принципиальная схема ПИД-регулятора

 

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

·   в блоке P происходит умножение соответствующего коэффициента пропорциональной составляющей на величину ошибки;

·   в блоке I происходит интегрирование ошибки и умножение полученной величины на коэффициент ;

·   в блоке D происходит дифференцирование ошибки с умножением на коэффициент ;

Уравнение ПИД регулятора:

 

,

(t) - выходная величина регулятора;(t) -сигнал рассогласования(ошибка);, I, D - пропорциональная, интегральная и дифференциальная составляющие;

 - коэффициенты ПИД регулятора;

Распространены также следующие модификации уравнения ПИД регулятора:

 

,

,

 

Взаимосвязь коэффициентов, входящих в выражения и существует, но отсутствие общепринятой системы параметров почти всегда приводит к путанице. Если происходит замена одного ПИД регулятора на другой или же если происходит настройка параметров - это нужно учесть.


 

Пользуясь преобразованием Лапласа при нулевых начальных условиях, представим передаточную функцию ПИД регулятора в операторной форме:

 

,

 

.

На рис. 4 изображены амплитудно-частотная(АЧХ) и фазо-частотная(ФЧХ) характеристики операторной передаточной функции. В области нижних частот АЧХ и ФЧХ определяются интегральным членом, в области средних частот - пропорциональным, в области высоких - дифференциальным[3].

 

Рис.4. АЧХ и ФЧХ ПИД-регулятора

 

Вид АЧХ и ФЧХ регулятора определяет его точность и запас устойчивости. Из рисунка 2 следует, что при уменьшении интегральной составляющей , происходит увеличение модуля коэффициента усиления регулятора на нижних частотах (то есть при приближении к установившемуся режиму), следовательно, погрешность «e» начинает снижаться.

При повышении дифференциальной компоненты происходит усиление на высоких частотах, что влечёт за собой усиление шумов измерений и внешних возмущений. Исходя из этого следует, что дифференциальную составляющую используют только для улучшения формы переходного процесса в системе, тогда как её практическая реализация зачастую содержит фильтр высоких частот(ФВЧ).

 

Рис.5. ПИД-регулятор в системе с шумом и внешними возмущениями f(t)

 

Повышение пропорционального коэффициента K влечёт за собой увеличение модуля петлевого усиления контура регулирования, а также увеличение точности во всём диапазоне частот, однако запас по фазе и усилению начинает снижаться, что ухудшает робастность и качество регулирования системы, а при дальнейшем увеличении пропорциональной составляющей K возникают периодические колебания (система теряет устойчивость). Воздействие помех измерений f и шума снижается с ростом петлевого усиления и пропорционального коэффициента.

 

Полетный контроллер

 

Полетный контроллер - это основная плата управления, обеспечивающая функционирование мультикоптера. В качестве вычислительного центра платы управления используется микроконтроллер, зачастую это либо маломощные Atmega328, либо более современные, Atmega2560 или ARM-контроллеры (STM32)

К функциям полетного контроллера относятся:

·   Стабилизация аппарата в воздухе

·   Удержание высоты (при помощи барометра) и позиции (при помощи GPS)

·   Автоматический полет по заданным заранее точкам (опционально)

·   Передача на землю текущих параметров полета с помощью модема или Bluetooth (опционально)

·   Обеспечение безопасности полета (возврат в точку взлета при потере сигнала, автопосадка)

·   Подключение дополнительной периферии: OSD, светодиодной индикации и пр.

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

Используемый в данном проекте полетный контроллер ArduPilot Mega является полноценным решением БПЛА, который позволяет помимо радиоуправляемого дистанционного пилотирования - автоматическое управление по заранее созданому маршруту, т.е. полет по точкам, а также обладает возможностью двухсторонней передачей телеметрических данных с борта на наземную станцию (телефон, планшет, ноутбук, DIY) и ведение журнала во встроенную память.

Он основан на автопилоте APM 2.x, разрабатываемым сообществом DIY Drones и базирующийся на open-source проекте, позволяющий превратить любой аппарат в автономное средство и эффективно использовать его не только в развлекательных целях, но и для выполнение профессиональных проектов.

Особенности:

·   3 осевой гироскоп, акселерометр, магнитометр и высокоточный барометр

·   Система стабилизации с возможностью воздушной акробатики

·   Удержание позиции по GPS, полет по точкам и возврат на точку старта

·   Возможность использования инфракрасного датчика для обхода препятствий

·   Поддержка ультразвукового датчика (sonar sensor) для автоматического взлета и посадки

·   Автоматическое следование по маршрутным точкам

·   Управление двигателями посредством ШИМ (PWM) с использованием дешевых регуляторов скорости (ESC)

·   Собственная система стабилизации для камеры (функция контроллера подвеса)

·   Радиосвязь и телеметрия с борта

·   Поддержка множества рам и конфигураций аппаратов

·   Поддержка датчика уровня заряда батареи

·   Настраиваемая световая индикация при полетах

·   Совместим с многими радиоуправляемыми приемниками PWM и PPM сигналов

·   Передача в реальном времени телеметрических данных

·   Поддержка OSD телеметрии (наложение на видеопередачу телемерических данных) используя протокол MAVLINK

·   Конфигурирования точек полета посредством Google Maps

·   Бортовая флеш память 16Мбит для автоматической регистрации данных

·   Цифровой компас работает на HMC5883L (до версии 2.5.2)

·   6 степеней свободы в InvenSense акселерометре, гироскоп MPU-6000

·   Контроллер Atmel ATmega2560-16AU и ATMEGA32U-2 чип для обработки и функции USB

·   Возможно загрузка обновлений встроенного программного обеспечения и конфигурации

Ниже описаны некоторые режимы полета, доступные контроллеру:

·   Stabilize - удержание горизонта,

·   AltHold - удержание высоты,

·   Loiter -«замри и слоняйся»,

·   Return-to-Launch - вернуться на точку старта,

·   Auto - выполнение заданного маршрута в автоматическом режиме,

·   Acro - акробатика (отключение всех стабилизационных систем),

·   Circle - облет по кругу заданного радиуса,

·   Position - фиксация в воздухе с ручным газом взлета

·   Land - автоматическая посадка

·   Simple - «легкий» полет

Контроллер предусматривает возможность самостоятельно программировать режимы полета.

 

Фильтр Калмана

В практической части работы используется алгоритм фильтрации, называемый фильтром Калмана. Это один из самых действенных методов фильтрации данных в частности в робототехнике.

Фильтр Калмана использует динамическую модель системы (например, физический закон движения), известные управляющие воздействия и множество последовательных измерений для формирования оптимальной оценки состояния. Алгоритм состоит из двух повторяющихся фаз: предсказание и корректировка. На первом рассчитывается предсказание состояния в следующий момент времени (с учетом неточности их измерения). На втором, новая информация с датчика корректирует предсказанное значение (также с учетом неточности и зашумленности этой информации)

 


 

Рис.6. Схема фильтра Калмана

 

Уравнения представлены в матричной форме. В случае с одной переменной матрицы вырождаются в скалярные значения.

В данных обозначениях: подстрочный индекс обозначает момент времени: k - текущий, (k-1) - предыдущий, знак «минус» в верхнем индексе обозначает, что это предсказанное промежуточное значение.
Описание переменных представлены на следующих изображениях[4]:

 

Рис.7. Уравнение предсказания

 

Рис.8. Уравнение корректировки

 


 

Библиотека OpenCV

 

В данном разделе представлены данные о библиотеке OpenCV - основного инструмента для разработки проекта. OpenCV - это одна из библиотек для работы с компьютерным зрением (библиотекой в программировании называется сборник подпрограмм или объектов, используемых для разработки программного обеспечения). OpenCV реализована на C/C++, также разрабатывается для Python, Java, Ruby, Matlab, Lua и других языков. Может свободно использоваться в академических и коммерческих целях - распространяется в условиях лицензии BSD. Библиотека довольно популярна, на текущий момент имеет более 5 миллионов скачиваний и недавно была предложена в качестве основы для стандарта Khronos по компьютерному зрению. Примечательно, что OpenCV был разработан программистами из российского отделения компании Intel.

 

Классы библиотеки 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 - калибровка камеры, поиск стерео-соответствия и элементы обработки трёхмерных данных.

 


 

Захват видеосигнала

 

Первой задачей стал вывод на экран компьютера видеопотока с камеры. Сделать это можно и без использования библиотеки OpenCV, но мы сразу будем использовать её возможности. В классе Main создадим метод start, который будет производить действия для предварительной подготовки программы. В этом методе мы создаем объект класса FXMLLoader, указываем ему путь на FXML-файл с разметкой и назначаем его «родителем» (Parent). Отныне каждый объект, находящийся в программе будет являться классом-«ребенком» (Child) и подчиняться FXML-файлу и его контроллеру. Затем создается объект класса Stage (а так же дочерний объект класса Scene, который является окном программы в системе Microsoft Windows) и задаются его параметры - заголовок, размеры, возможность изменять размеры окна. Затем методом Stage.show окно вызывается для взаимодействия с пользователем.

Выполнив эти действия, метод передает управление классу controller.java, в котором содержится основной код программы. В этом месте нужно создать объекты для всех элементов программы. Это объекты классов Button (графическая кнопка включения и выключения камеры), ImageView (класс, предназначенный для вывода изображений на экран), ScheduledExecutorService (таймер для контроля видеопотока) и VideoCapture (класс OpenCV, захватывающий видео с камеры).

Запрограммируем метод private Mat grabFrame, захватывающий видеопоток. Как мы знаем, слово перед названием метода означает тип данных переменной, которую возвращает этот метод. В данном случае это не стандартная переменная, а объект класса Mat, содержащегося в библиотеке OpenCV. В нашем случае это будет объект frame - одно изображение, взятое из видеопотока. Итак, в методе private Mat grabFrame создаем объект frame класса Mat. С помощью метода this.capture.isOpened программа проверяет, поступает ли с порта камеры изображение, и, если да, то применяет метод this.capture.read (frame), который записывает кадр в объект, а если нет, то выдает ошибку. Далее идет проверка, содержит ли кадр какую-либо информацию, и, если содержит, то над ним будут проводиться необходимые преобразования, которые мы пропишем позже. Пустой же кадр метод возвращает без изменений.

Следующий необходимый метод обрабатывает событие, возникающее при нажатии кнопки Start Camera. Назовем его void startCamera (ActionEvent event). Как мы можем увидеть, этот метод принимает как аргумент событие нажатия кнопки и не возвращает никаких значений.

Как только кнопка оказывается нажатой, метод активируется и сначала применяет метод this.capture.open (cameraId), включающий захват с камеры с номером cameraId. Если захват включён, то функция frameGrabber с помощью упомянутого ранее таймера захватывает изображение с потока раз в 33мс (30 кадров в секунду). Тут же производится и перенос изображения из объекта класса Mat в объект класса Image. Так же в методе предусмотрен вывод сообщений об ошибке, процедура закрытия программы, изменений надписи на кнопке, в зависимости от состояния камеры (включена или выключена).

Теперь в FXML-файле нужно создать разметку: в текстовом виде или с помощью утилиты SceneBuilder. В объекте класса Scene, который является окном программы в операционной системе Microsoft Windows, создадим связанные элементы GridPane и BorderPane. Они служат для удобной расстановки элементов управления по рабочему пространству программы. Так же необходимо создать объект класса ImageView для показа захватываемого изображения на экран и объект класса Button для включения и выключения камеры.

 

Рис. 16. Интерфейс программы в утилитеSceneBuilder

 

Представленная на Рис. 17 программа - результат на данный момент. Пока она умеет лишь захватывать видео с камеры и выводить его на экран. Так же имеется кнопка Start/Stop Camera, которая соответственно включает и выключает камеру.

 

Рис. 17. Программа, захватывающая видеосигнал с камеры

 

Обработка изображения

 

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

В первую очередь, информация о цвете изображения является избыточной и нет нужды тратить вычислительные мощности на ее обработку. Тем более, она может не только оказаться ненужной, но и навредить, уменьшая эффективность распознавания объекта. Так же многие методы библиотеки OpenCV в принципе могут работать только с двухцветными изображениями. Поэтому в большинстве проектов по распознаванию объектов изображение переводится в бинарный вид (черные и белые пиксели без оттенков серого). Часто этот перевод происходит с помощью семплирования цвета - в таком случае программа запоминает определенный цвет и переводит все пикселы с цветами, имеющими похожий цвет, в белый, а все остальные пикселы - в черный. Однако в данном случае этот метод является излишним, так как предполагается только распознавание темного предмета на светлом фоне. Итак, как мы знаем, результатом захвата видеосигнала является объект frame класса Mat. Создадим метод, преобразующий его в двоичный вид и назовем его imageEdit. В результате всех преобразований над изображением оно должно максимально полно передавать информацию о положении объекта, то есть в идеале полностью обозначать объект одним из цветов, а фон - другим.

Первое необходимое действие - перевод изображения в монохромный вид. Оно производится методом Imgproc.cvtColor, который принимает три аргумента: объект изображения-источника, объект, в который записывается преобразованное изображение и тип преобразования. В качестве первых двух выберем объект frame, а типом преобразования будет COLOR_BGR2GRAY. Теперь для получения бинарного изображения, нужно произвести пороговое преобразование. За это отвечает метод Imgproc.threshold, который имеет пять аргументов: два первых повторяют аналогичные для Imgproc.cvtColor, третий - величина порога выбора цвета, четвертый - максимальное значение переменной, а пятый - тип преобразования (метод поддерживает различные алгоритмы, из который мы выбираем находящийся под номером один, в котором пиксел перекрашивается в белый цвет, если значение его яркости меньше порогового значения, и в черный в другом случае). Значение порога не может быть выбрано раз и навсегда, так как оно должно зависеть от внешних условий, таких как освещение. Поэтому добавим объект класса Slider в класс controller и в файл разметки. В нем же устанавливаются максимальное, минимальное значения и значение по умолчанию для слайдера. Теперь команду slider.getValue можно вставить в качестве третьего аргумента метода порогового преобразования и управлять величиной порога непосредственно с экрана.

Теперь изображение имеет бинарный вид, но необходимо произвести еще одно преобразование - размытие, защищающее от помех. Оно производится методом Imgproc.medianBlur. Аналогично с пороговым преобразованием, создадим слайдер, управляющий глубиной размытия и эмпирически выберем оптимальный тип алгоритма для данной задачи.

 

Рис. 18. Внешний вид программы после редактирования изображения

 


Выделение контуров

 

Добившись результата, в котором программа выдает качественное бинарное изображение руки, можно приступать к анализу этого изображения. Сейчас для компьютера оно представляет собой двоичный массив, в котором черные пиксели можно считать за состояние true, а белые - за состояние false. Наша задача - анализ информации, содержащейся в этом массиве и вынесение решения согласно этой информации. Алгоритм должен состоять из двух частей: первая каким-то образом структурирует информацию, содержащуюся в изображении, представляет всю полезную часть информации в виде определенного блока данных. Вторая часть сравнивает эти данные с определенными константами, заданными программистом. Если обработанные данные соответствуют какой-то из констант, то программа возвращает определенный результат, иначе - сообщение об ошибке или отсутствии необходимого типа изображения.

Самый примитивный вариант реализации - полностью игнорировать первый шаг, оставив данные в массиве двоичных переменных и сравнивать этот массив с заранее записанным в программу изображением какого-либо жеста. В таком случае используемый метод фактически представляет собой корреляционный прием: значение каждого пиксела полученного изображения перемножается со значением соответствующего пиксела заданного изображения. Затем эти значения суммируются и по этой сумме можно делать вывод о степени «похожести» двух изображений. Этот метод прост для программирования, но чрезвычайно неэффективен: из-за различных вариаций захваченного изображения (масштаб, положение руки, индивидуальные особенности каждого пользователя) метод будет давать существенные ошибки [11]. Поэтому в данном проекте мы перейдем от анализа пикселей к анализу контуров.

Стоит обговорить, какую информацию следует выделить из изображения для дальнейшей обработки. Начать следует с самых простых жестов - когда плоскость ладони перпендикулярна камере и в качестве переменных для вычислений используется только длины пальцев (прижат тот или иной палец или нет) и углы между пальцами. Для получения всей этой информации достаточно найти на изображении несколько точек, называемых экстремальными: кончик каждого пальца и каждую перепонку между пальцами. В таком случае необходимо создать два контура: один точно очерчивает руку, а другой соединяет крайние точки в многоугольник. В таком случае точки на кончиках пальцев - это и есть точки, по которым следует построить обводящий контур, а точки между пальцами можно найти как максимальные отклонения одного контура от другого. Значит сначала нужно найти и нарисовать оба контура, а затем производить операции над ними. Далее контур, повторяющий форму руки, будем называть внутренним (в программе он значится как contour), а контур, соединяющий экстремальные точки объекта в многоугольник, будем называть обводящим (или convexHull). Естественно, на изображении может быть целое множество контуров, и все контуры того или иного вида объединяются в массив, каждый элемент которого является, в свою очередь, массивом точек или иных типов переменных. Таким образом, и contour, и convexHull - это двухмерные массивы, и каждый отдельный контур можно выделить с помощью метода get(i), где i - номер контура [9].

Дополним метод обработки изображения командами, которые будут находить контуры изображения и графически выделять их на рабочем поле. Для начала пропишем команду LinkedList<MatOfPoint> contours = new LinkedList<>. Она создает массив объектов класса MatOfPoint - это тип данных, хранящий в себе положение множества точек на двухмерном пространстве изображения. Значит каждый контур будет обрабатываться программой, как массив точек, находящихся на определенной кривой. Затем с помощью команды contours.clear убедимся, что заданный массив пуст. Далее применяется метод findContours из класса Imgproc. Он, используя определенные алгоритмы, выделит контуры на порогах белого и черного цветов и запишет их в массив contours. Настройки алгоритма задаются двумя атрибутами: мы выбираем Imgproc.RETR_EXTERNAL для того, чтобы сообщить программе, что следует игнорировать внутренние контуры и выделять следует только наружные. Второй атрибут характеризует сам тип используемого алгоритма и эмпирическим путем было выявлено, что оптимально подходит Imgproc.CHAIN_APPROX_TC89_KCOS.

Далее произведем фильтрацию: интерес для анализа представляет только один объект, так что из всех выделенных контуров можно выбрать единственный с наибольшей площадью. Поэтому создадим новый объект MatOfPoint finalContours, он будет хранить в себе наибольший контур, который программа будет отрисовывать и над которым будут проводиться дальнейшие операции. Запишем в его первый элемент изначального массива контуров, а затем циклом будем проверять каждый последующий элемент contours и, если возвращенное методом Imgproc.contourArea значение площади будет превосходить значение площади единственного элемента finalContours, то элемент finalContours будет принимать значение элемента contours. Таким образом мы получили объект, содержащий только контур вокруг самого большого предмета на изображении.

В конце пропишем метод, рисующий все контуры на рабочем поле, Imgproc.drawContours. Его параметры не представляют особого интереса: это поле, в котором нужно рисовать, массив самих контуров, цвет и толщина линий.

Нахождение обводящего контура - менее тривиальная задача. Дело в том, что библиотека OpenCV умеет оперировать множеством типов переменных и массивов, причем разные ее методы требуют применения разных типов. Поэтому нередко приходится применять весьма нетривиальные преобразования, особенно реализации библиотеки для языка Java: многие операции, в отличие от реализаций для других языков программирования, здесь приходится производить вручную.

Как мы помним, контур, очерчивающий объект, программа воспринимает как массив класса MatOfPoint, содержащего в себе координаты каждой точки данного контура. Однако объект обводящего контура задается совершенно другим путем - метод Imgproc.convexHull находит не контур, а каждую крайнюю точку изображения как элемент массива MatOfInt, состоящего из целых чисел, тогда как для графического изображения пригоден только массив MatOfPoint. Итак, для единственного оставшегося после фильтрации внутреннего контура нужно создать элемент массива с помощью метода convexHull.add(new MatOfInt), а также применить сам метод Imgproc.convexHull, отыскивающий обводящий контур вокруг внутреннего, причем в атрибутах метода должны находиться нулевые элементы массивов contour и convexHull, которые выделяются с помощью метода get. В результате массив convexHull наполняется обводящим контуром.

Теперь преобразуем его в необходимый формат, MatOfPoint. Преобразование идет сначала из формата библиотеки OpenCV MatOfInt в обычный двухмерный массив переменных типа Point, и только потом непосредственно в формат MatOfInt. Создадим массив класса Point и назовем его hullpoints. Затем в каждом шаге цикла от нуля до количества обводящих контуров создадим новую точку в массиве и еще одним циклом присвоим новое значение с помощью метода convexHull.get. Массив же в формате MatOfPoint обозначим как hullmop и еще одним циклом по всем элементам hullpoints проведем преобразование. Происходит это тремя командами: создается объект MatOfPoint, затем метод fromArray(hullpoints.get) передает ему соответствующее счетчику значение массива hullpoints, затем метод hullmop.add записывает этот объект в соответствующий массив. [5]

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

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

 

Рис. 19. Программа после выделения контуров

 

Фильтрация точек дефектов

 

Прежде чем приступать к анализу найденных точек, необходимо отфильтровать результаты, так как не все из них несут полезную информацию. Нужно, во-первых, исключить все точки defect, образующие с соседними точками start и end слишком большой угол, так как даже максимальный угол отклонения между указательным и большими пальцами не может превышать π/2 и эти точки не несут в себе информации о положении пальцев. Во-вторых, нужно исключить точки start, которые находятся слишком близко друг к другу, так как алгоритм может ошибочно выделять несколько рядом стоящих точек и один палец будет считаться за два. И, в-третьих, нужно исключить точки, находящиеся в непосредственной близости к краю изображения, ведь, как показывает практика, алгоритм часто дает просчеты и в этих областях. Для работы с каждым из трех массивов точек создадим еще по два массива - x и y координат соответственно. Назовем их соответственно startX, startY,endX, endY, defectX, defectY, и присвоим им тип double. Наполнить их информацией о соответствующих координатах каждой точки можно с помощью цикла по всем индексам точек. Далее условными операторами будем производить фильтрацию. Сделаем внутри цикла оператор if с тремя условиями прохождения фильтрации. Если координаты точек defect и start с неким порядковым номером будут отвечать заданным условиям, то эти точки будут записаны в новые массивы, названные defectFiltered и startFiltered. Эти условия будут объединены как логические элементы «и», то есть присвоение случится только если все три условия одновременно будут выполнены.

Первое условие - это достаточно малая величина угла между двумя точками start и точкой defect, находящейся между ними. В java и OpenCV не существует стандартной функции для нахождения угла, описанного тремя точками, поэтому придется сделать ее самостоятельно. По теореме косинусов можно найти любой угол треугольника, если известно три его стороны. Поэтому построим воображаемый треугольник из точекstart,defectиendи вычислим длины его сторон, зная координаты точек. Затем применим теорему косинусов и запишем значение угла в переменную angle. Теперь можно создать первое условие - точка будет записываться в конечный массив только когда значение угла меньше определенного значения. Пока остановимся на значении π/2.

Второе условие - это достаточно б<


Поделиться с друзьями:

Папиллярные узоры пальцев рук - маркер спортивных способностей: дерматоглифические признаки формируются на 3-5 месяце беременности, не изменяются в течение жизни...

Своеобразие русской архитектуры: Основной материал – дерево – быстрота постройки, но недолговечность и необходимость деления...

Таксономические единицы (категории) растений: Каждая система классификации состоит из определённых соподчиненных друг другу...

История развития хранилищ для нефти: Первые склады нефти появились в XVII веке. Они представляли собой землянные ямы-амбара глубиной 4…5 м...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.118 с.