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

  • Вид работы:
    Курсовая работа (т)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    22,69 Кб
  • Опубликовано:
    2017-05-20
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

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

Минобрнауки России

федеральное государственное бюджетное образовательное учреждение

высшего образования

«Иркутский государственный университет»

(ФГБОУ ВО «ИГУ»)







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




Введение

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

Компьютерное зрение - это сложная деятельность, которая подразумевает наличие глубоких знаний в программировании, обработке сигналов, статистике и т.д. В данной работе мной было начато изучение технологий компьютерного зрения на примере создания сравнительно простой программы для распознавания жестов руки. Основой для разработки послужила библиотека OpenCVс открытым исходным кодом.

1. Компьютерное зрение

В данном разделе даны основные теоретические сведения о рассматриваемом предмете.

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

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

Компьютерное зрение - это очень молодая и динамично развивающаяся область компьютерной технологии. Первые разработки в этой области появились только в начале 1970-х годов. Главной причиной этому служит то, что методы, обычно используемые в алгоритмах компьютерного зрения достаточно требовательны к вычислительной мощности машин - почти всегда приходится иметь дело с большими по временам рассвета цифровой эры массивами данных. Так же по причине относительной новизны технологии и происхождения её из многих других областей компьютерной науки, не существует стандартной формулировки проблемы компьютерного зрения, и, более того, не существует стандартного решения этой проблемы. Методы и алгоритмы компьютерного зрения очень сильно зависят от конкретно поставленной задачи и могут кардинально отличаться друг от друга. Компьютерное зрение во многом происходит от таких областей, как статистика, методы оптимизации и обработка сигналов, а также тесно пересекается с ними. [1]

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

Главная сложность технологий компьютерного зрения и, в то же время, причина необходимости их создания, состоит в том, что любая электронно-вычислительная машина лишена абстрактных категорий и способна работать только с конкретными величинами. Компьютер не «понимает», что такое форма, текстура, размер или даже цвет, его можно только «научить» работать с этой информацией, определенным образом закодировав её в последовательность нулей и единиц.

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

Компьютерное зрение не рассматривает технологии создания цифровых изображений, описывая лишь их обработку, поэтому опустим подробности и остановимся на том, что устройство захвата (цифровая камера), используя светочувствительные элементы формирует изображение (фото) или последовательность изображений (видео) реальных объектов. «Изображение» для компьютера - это определенным образом закодированный массив чисел.

Рис.1. Представление зрительной информации компьютером

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

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

Эти алгоритмы могут выполнять различные действия - от очень простых, наподобие подсчета каких-либо признаков, до гораздо более сложных действий, связанных с распознаванием, определением местоположения и контролем объектов. Для формирования бинарного изображения B по данным полутонового или цветного изображения I можно выполнить операцию, которая выбирает некоторое подмножество пикселов изображения в качестве пикселов переднего плана (foreground pixels). Эти пикселы представляют интерес для решаемой задачи анализа изображений. Остальные пикселы игнорируются как фоновые (background pixels). Операция отбора пикселов может быть простой (например, пороговый оператор, который отбирает пикселы со значениями из заданного яркостного диапазона или цветового подпространства) или представлять собой сложный алгоритм классификации. [2]

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


Рис. 2. Бинарное изображение рукописных символов

Пикселы бинарного изображения B принимают значения 0 или 1. Будем полагать, что значения 1 соответствуют пикселам переднего плана, а 0 - фоновым пикселам. Значение пиксела на пересечении строки r и столбца c пиксельного массива обозначается как B [r, c]. Изображение размерами M × N состоит из M строк, пронумерованных от 0 до M − 1, и N столбцов, пронумерованных от 0 до N − 1. Таким образом, обозначение B [0, 0] соответствует значению левого верхнего пиксела изображения, а B [M − 1, N − 1] - значению правого нижнего пиксела. Во многих алгоритмах при обработке пикселов учитываются не только их значения, но и значения соседних пикселов. При рассмотрении соседних пикселов часто используются два определения окрестностей - четырехсвязная и восьмисвязная окрестности. Четырехсвязная окрестность N4 [r, c] пиксела [r, c] состоит из пикселов [r − 1, c], [r + 1, c], [r, c − 1] и [r, c + 1]. Они часто называются, соответственно, северным (north), южным (south), западным (west) и восточным (east) соседями. Восьмисвязная окрестность N8 [r, c] пиксела [r, c] содержит все пикселы четырехсвязной окрестности, а также диагональные соседние пикселы [r − 1, c − 1], [r − 1, c + 1], [r + 1, c − 1] и [r + 1, c + 1]. Их можно соответственно называть северо- западным (northwest), северо-восточным (northeast), юго-западным (southwest) и юго-восточным соседями (southeast). Расположение соседних пикселов в окрестностях двух типов демонстрируется на рис. 3. [3]


Рис. 3. Четырехсвязная и восьмисвязная окрестности пикселов

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

Вообще методы обнаружения можно условно разделить на три основные группы:

− скелетные методы;

− методы на основе 3D модели объекта;

− методы на основе 2D модели объекта.

В скелетных методах исследуется контур силуэта: обычно отыскиваются углы, выступы, впадины и другие точки с высокими значениями кривизны. Для получения информации о форме контура применяются различные представления границы объекта. В методах на основе 3D модели руки представляют в виде сложных трехмерных поверхностей и классифицируются с помощью нейронных сетей Метод 2D распознавания схож с предыдущим, но использует двумерное изображение вместо объемных моделей. Каждый из методов имеет преимущества и недостатки. Недостатком метода на основе 3D модели является его ресурсоемкость. Построение 3D модели, обучение нейронной сети и ее использование могут потребовать значительных ресурсов, так же не стоит забывать, что для использования данного метода требует камеры с возможностью определения глубины изображения.

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

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

После выделения контура в бинарный вид, он подвергается процедуре скелетизации (утоньшению). Каждый последовательный контур скелетного представления описывается в виде последовательного набора особых точек и так называемого цепного кода, состоящего из точки привязки, числа кодов и массива направлений из очередной точки на следующую точку. Особые точки - это концевые точки и точки ветвления (триоды), т.е. точки, соседи которых образуют не менее трех связных областей. На рис. 4 изображен образ, обладающий двумя внутренними контурами, одной концевой точкой и тремя триодами. [4]

Рис. 4. Образ, прошедший процедуру скелетизации

В полученном описании производится огрубляющая предобработка, состоящая в удалении коротких линий, объединении близких триодов, уничтожении малых внутренних контуров. Для внешнего контура находится его тип или топологический код. Для этого контур записывается в виде последовательного набора номеров особых точек, соответствующих обходу по часовой стрелке. Затем с помощью пере нумерации делается попытка отождествления контура с одним из основных типов. [2]


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

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

.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 чрезвычайно полезны, потому что существенно упрощают код. Они позволяют перейти от объектов, привычных в численных вычислениях к объектам, необходимым для работы с изображениями.

2.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. Библиотека предоставляет несколько простых функций, которые позволяют открывать окно и отображать в нем изображения. Тут же (в окне) существует возможность обрабатывать события, поступившие от мыши и клавиатуры. [6]

ML - модели машинного обучения (SVM, деревья решений, обучение со стимулированием и т. д.).

Features2d - распознавание и описание плоских примитивов (SURF, FAST и другие, включая специализированный фреймворк).

Video - анализ движения и отслеживание объектов (оптический поток, шаблоны движения, устранение фона).

Objdetect - обнаружение объектов на изображении (нахождение лиц с помощью алгоритма Виолы-Джонса, распознавание людей HOG и т. д.).

Calib3d - калибровка камеры, поиск стерео-соответствия и элементы обработки трёхмерных данных.


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

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

В контроллерах, управляющих беспилотными дронами сообщение, сигнализирующее о необходимости переключить режим, передается по отдельным каналам, которые так же обрабатывается средствами временного уплотнения. Таким образом, общий сигнал состоит из нескольких широтно-импульсно промодулированных сигналов, разделенных по времени. Сначала передаются импульсы, исходя из длины которых контроллер подает напряжение на двигатели, а за ними - импульсы, длина которых сигнализирует о активности того или иного режима полета. Идея состоит в том, чтобы переключение режимов так же, как и управление положением дрона, перенести с пульта на интуитивно понятные жесты рук и избавиться от необходимости использовать еще какие-либо устройства и переключатели. Значит программа должна каким-то образом распознавать жест, показанный пользователем, возвращать результат (определенный код для каждого предусмотренного жеста), затем этот результат передавать в программу, анализирующую показания датчиков и формирующую сигнал для передачи на квадрокоптер. Эта задача является достаточно сложной в плане производительности - жест руки снимается на видео и затем видеосигнал анализируется сложными алгоритмами, требующими значительных вычислительных мощностей. Микроконтроллер AVR для этих целей не подойдет, а персональный компьютер обладает слишком низкой мобильностью для практического применения устройства. Поэтому идеальным вариантом бы стал мобильный телефон на системе Android: мы можем создать приложение, захватывающее видеосигнал с камеры устройства, обрабатывающее его и передающее результат по протоколу Bluetooth на основной модуль устройства. Поэтому для разработки был выбран язык программирования, используемый в разработке приложений для Android - Java. Первый вариант программы, для упрощения отладки и тестирования, создан как приложение с графическим интерфейсом на языке JavaFX для платформы IBM PC, но в будущем перенос приложения на Android не займет много сил и времени, так как Java является мультиплафтормерным языком программирования. Функционал первой версии программы пока будет ограничен подсчетом загнутых пальцев и проверкой состояния руки (соединены ли пальцы вместе или раздвинуты).

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

Рис. 5. Принципиальная схема программы

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

Для программы был создан проект на платформе JavaFX в среде разработки IntelliJ IDEA. JavaFX по своей сути есть платформа для создания приложений на языке Java с графическим интерфейсом. Для создания интерфейсов существует файл на языке разметки FXML, который «общается» с программой на Java с помощью класса controller.java. FXML-файл описывает положение, размеры, графическое оформление всех элементов программы, а controller.java связывает элементы в программный код.

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

Первой задачей стал вывод на экран компьютера видеопотока с камеры. Сделать это можно и без использования библиотеки 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 для включения и выключения камеры.

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

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

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

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

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

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

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

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

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

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

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

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

Дополним метод обработки изображения командами, которые будут находить контуры изображения и графически выделять их на рабочем поле. Для начала пропишем команду 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. Выберем для его отображения другой цвет и толщину линий. В результате программа имеет данный вид. В результате программа имеет вид, показанный на рис. 9.

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

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

Теперь найдем так называемые дефекты обводящего контура. Создадим очередной массив-объект для хранения информации, на сей раз в формате MatOfInt4, под названием convDef. Этот массив хранит данные сгруппировано по четыре числа формата Integer. Используется этот формат потому что для описания каждого дефекта метод выделяет по четыре величины: start, end, defect, depth.

Рис. 10. Схематичное изображение возвращаемых значений метода Imgproc.convexityDefects

Для полноценного описания в данном проекте достаточно точек start, end и defect. Для удобства создадим так же обычный одномерный массив типа Integer и назовем его cdList. Методом Imgproc.convexityDefects выделим массив дефектов обводящего контура. Метод имеет три атрибута: внутренний, контур, обводящий контур, и объект в который будет записываться информация, convDef. Но формат IntOfMat4 неудобен для использования и не принимается методами рисования, поэтому переведем всю информацию в обычный массив data методом convDef.get(0).toList. Также создадим массив cdList, который наполнится натуральными числами от нуля до количества дефектов умноженное на четыре. Теперь информация записана так: в нулевом элементе находится число, характеризующее start первого дефекта, в первом - end первого дефекта, во втором defect первого дефекта, в третьем - depth первого дефекта, в четвертом - start второго дефекта и так далее. Теперь создадим три массива типа Point, в одном из них будут храниться все точки start, во втором все точки end, а в третьем - все точки defect.

После этого можно сразу создать цикл, рисующий все точки из массивов на экране, на этот раз методом Imgproc.circle и посмотреть на соответствующий результат.

Рис. 11. Вид программы с найденными экстремальными точками

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

Прежде чем приступать к анализу найденных точек, необходимо отфильтровать результаты, так как не все из них несут полезную информацию. Нужно, во-первых, исключить все точки 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.

Второе условие - это достаточно большое расстояние между точками start. Если расстояние между двумя точками будет меньше определенного значения, то только одна из них должна записаться в конечный массив, поэтому с помощью цикла сравним каждую точку start [i] с точкой start [i+1]. При сумме квадратов координат больше определенного значения, точка записывается в конечный массив.

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

Рис. 12. Вид программы после фильтрации точек дефектов

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

Итак, теперь мы имеем достаточно много информации о положении руки: каждый из пяти пальцев обозначен точкой из массива, причем номер пальца, считая слева направо, соответствует номеру элемента массива. Четыре промежутка между пальцами так же обозначены точками из другого массива. В дальнейшем, обрабатывая эту информацию, можно получать разнообразные результаты. Для примера усовершенствуем код, чтобы программа выводила на экран количество неприжатых пальцев, и, если пальцы соединены, меняла цвет внутреннего контура на красный. Информация о количестве пальцев уже присутствует в программе - это размер массива startFiltered. Преобразуем ее в тип данных String и выведем на экран методом Imgproc.putText. Метод для вычисления углов тоже уже был создан в процессе произведения фильтрации, поэтому воспользуемся им, только на этот раз суммируем все углы циклом и выведем их среднее арифметическое. Среднее арифметическое теперь снова можно сравнить с порогом, только теперь при его значении меньше порога объект класса Scalar, отвечающий за цвет внутреннего контура, будет менять свои атрибуты. Конечный результат можно наблюдать на рис. 14.

Рис. 13. Конечный вариант программы


Заключение

Результатом работы стала программа, способная различать простейшие жесты руки. Ее реализация далека от идеала и требует существенной доработки. По мере прохождения практики и освоения компьютерного зрения и библиотеки OpenCV, на каждом шаге приобретались новые знания и каждый шаг алгоритма, с высоты приобретенного опыта, безусловно, следует оптимизировать. В первую очередь нужно добавить в программу систему распознавания объекта по цвету, чтобы повысить помехоустойчивость, улучшить алгоритм фильтрации и более сделать управление оперативной памятью более рациональным. Нужно «научить» программу распознавать новые, более сложные жесты и оптимизировать распознавание уже имеющихся. В перспективе также слияние проекта с другими методами управления робототехническими устройствами, и создание интуитивно понятной системы управления беспилотным летательным аппаратом.

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

1.Форсайт Д.А. Компьютерное зрение. Современный подход. / Д.А. Форсайт, Ж. Понс. - М : Издательский дом «Вильямс», 2004. - 982 с.

2.Шапиро Л. Компьютерное зрение. / Л. Шапиро,000 Дж. Стокман.- М: Бином. Лаборатория знаний, 2013. - 752 с.

.Желтов С.Ю. Обработка и анализ изображений в задачах машинного зрения. / С.Ю. Желтов [и др.]; ред. С.Ю. Желтов.- М: Физматкнига, 2010. - 672 с.

.Лукьяница А.А.Цифровая обработка видеоизображений. / А.А. Лукьяница,А.Г. Шишкин. - М: «Ай-Эс-Эс Пресс», 2009. - 518 с.

5.G. Bradski. Learning OpenCV. /Gary Bradski and Adrian Kaehler. - M : OReilly Media, Inc, 2008. - 571 c.

.OpenCV documentation index [Электронный ресурс] : сайт. - URL: https://docs.opencv.org.

.E. R. Davies. Machine Vision: Theory, Algorithms, Practicalities. M: - Morgan Kaufmann, 2004. - 579 c.

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

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!