Бесконтактное управление техникой через алгоритмы распознавания

Анализ существующих проблем и обзор библиотеки обработки изображений и алгоритмов общего назначения OpenCV. Особенности разработки и детальный анализ требований к программе. Основная логика ее работы и реализация. Трекинг лица и объекта по цвету.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 26.06.2017
Размер файла 1,3 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

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

Размещено на http://www.allbest.ru/

ВВЕДЕНИЕ

Создание бесконтактных инструментов управления пользовательским интерфейсом является актуальной задачей. В данный момент ее пытаются решить такие крупные корпорации как Microsoft, Google, Apple, Intel и др. Можно выделить несколько наиболее популярных подходов к бесконтактному управлению: с помощью звуковых команд и с помощью визуальных данных. На данный момент наибольший интерес возникает к управлению компьютером с помощью визуальной информации, полученной с веб-камеры, так как именно визуальные данные наиболее информативны. Чтобы получить эти данные необходимо использовать специальные алгоритмы распознавания и отслеживания состояния объектов. Компания Intel предоставила такую возможность, выпустив библиотеку алгоритмов компьютерного зрения, обработки изображений и алгоритмов общего назначения OpenCV. Данная библиотека реализована на языках C++ и Python. программа изображение трекинг оpencv

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

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

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

Для реализации такой программы достаточно библиотеки компьютерного зрения OpenCV.

1. АНАЛИЗ СУЩЕСТВУЮЩИХ ПРОБЛЕМ И ОБЗОР БИБЛИОТЕКИ OpenCV

1.1 Дисплей

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

1.2 Курсор мыши

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

1.3 Обзор библиотеки OpenCV

OpenCV (Open Source Computer Vision Library) - библиотека алгоритмов компьютерного зрения с открытым исходным кодом. Распространяется свободно для коммерческих и академических целей в условиях лицензии BSD. В библиотеке реализованы алгоритмы распознавания с высокой вычислительной эффективностью с целью их работы в программах, обрабатывающих данные в реальном времени. OpenCV написана на языках C/C++, Python и поддерживает следующие операционные системы: Windows, Linux, Mac OS, iOS и Android.

На сегодняшний день последней версией библиотеки является версия 3.1. Всего же доступно для скачивания с официального сайта 15 версий, начиная с 1.0.0. Выпущено много промежуточных вариантов библиотеки версии 2.

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

Благодаря тому, что библиотека распространяется свободно для академических и коммерческих целей, появилось много книг и Интернет- ресурсов, которые рассказывают и наглядно показывают возможности применения OpenCV. Базовые принципы работы с библиотекой описывают авторы Гари Барски и Эдриан Кэхлер в книге Learning OpenCV (Robert Laganiere, OpenCV 2 Computer Vision Application Programming Cookbook, Published by Packt Publishing Ltd. 32 Lincoln road Olton Birmingham, B27 6PA, UK. May 2011) и автор Роберт Лаганир в книге OpenCV 2 Computer Vision Application Programming Cookbook (Robert Laganiere, OpenCV 2 Computer Vision Application Programming Cookbook, Published by Packt Publishing Ltd. 32 Lincoln road Olton Birmingham, B27 6PA, UK. May 2011). Единственное отличие между книгами заключается в том, что авторы первой дополнительно рассказывают об истории и причинах возникновения OpenCV, а также об общих идеях, подходах и проблемах компьютерного зрения. Однако, информация, содержащаяся в книгах, не является исчерпывающей, поэтому были задействованы Интернет- ресурсы такие как: stackoverflow (URL: http://stackoverflow.com) и github (URL: https://github.com).

2. РАЗРАБОТКА

2.1 Особенности разработки

Для реализации выбран язык C++ в связи с тем, что для программ распознавания очень важна скорость обработки данных, поэтому, из всех предложенных языков он наиболее подходящий (т.к. библиотека реализована на нем). Разработка велась в среде Visual Studio 2012, на компьютере со следующими характеристиками: процессор Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz 2.30 GHz, ОЗУ 4ГБ, 64-разрядная система. Также выбрана OpenCV версии 2.4.9 из-за того, что накоплен большой пользовательский опыт именно этого варианта библиотеки.

2.2 Детальный анализ требований к программе

Сформулируем требования к программе:

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

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

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

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

2.3 Основная логика работы программы

Из анализа требований к программе вытекает следующая архитектура данного программного решения:

1. Получение кадра из видеопотока.

2. Цветовая подготовка полученной картинки. Это требует OpenCV для работы алгоритмов распознавания.

3. Поиск лица пользователя, определение необходимости выключения экрана.

4. Поиск объекта для его трекинга и перемещения курсора.

5. Опрашивание системы на событие нажатой клавиши.

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

2.4 Реализация

Реализация данной архитектуры будет производиться по методу нисходящей разработки, сначала проектируются и реализуются модули программы, начиная с модуля самого верхнего уровня -- головного, далее разрабатываются модули уровнем ниже и т.д. Самым верхним уровнем в иерархии программы будет класс main.cpp. Далее следуют логически зависимые классы. Класс FaceDetector.cpp будет работать с трекингом лица. Для трекинга объекта по цвету будет создан класс ObjectColorDetector.cpp. Для отключения монитора и перемещения мыши будет создан класс SysstemCallerHelper.cpp. Логику инициализации необходимых ресурсов будет содержать в себе Initializer.cpp. Захват кадра из видео потока будет осуществлять FrameHelper.cpp.

Согласно разработанной логике программы вначале необходимо получить кадр. Этим будет заниматься метод getFrame. Далее, подготавливаем полученное изображение для трекинга объекта по цвету и распознавания лица. Этим будут заниматься методы getFrameForObjectTracking и getGrayFrame соответственно. Собственно, сама логика работы по распознаванию лиц и объектов по цвету реализована в методах detectFace и detectColorObject. Далее, для корректного трекинга объектов по цвету, необходимо вызывать цветовой сканер. Их в программе будет два: первый -- scanMode для автоматического определения, второй -- colorControlPanel для ручной настройки искомого цвета. Для их вызова будет использована стандартная OpenCV функция waitKey. Все это будет обернуто в бесконечный цикл, из которого можно выйти путем нажатия клавиши Esc. В результате получается следующая структура, продемонстрированная в листинге 1.

while(true)

{

getFrame(cap, bgrImage); //Получаем кадр из видеокамеры

depthMap = getFrameForObjectTracking(bgrImage); //Обрабатываем кадр для трекинга объекта grayscaleFrame = getGrayFrame(bgrImage); //Обрабатываем полученный кадр для трекинга лица excludedFaceROI = detectFace(grayscaleFrame, bgrImage); //Поиск лица, отключение монитора detectColorObject(bgrImage, depthMap, excludedFaceROI); //Трекинг объекта

wk = waitKey( 20 ); //Нажатие клавиши if( wk == 27 ) //ESC

{

break; //Выход

}

else if (wk == 32 )//Space

{

scanMode();//Запуск автоматичесского сканирования цвета

}

else if (wk == 67)//C

{

colorControlPanel();//Запуск ручного скинрования цвета

}

}

Листинг 1 - Тело основного цикла программы

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

2.5 Трекинг лица

Для начала рассмотрим возможности библиотеки обнаружить лицо человека. В OpenCV для решения задачи поиска лица на изображении используется каскадный детектор, работающий по методу Виолы - Джонса (Viola - Jones). В качестве простых классификаторов для каскада используются простые Хааровские классификаторы. Сейчас метод Виолы - Джонса является одним из самых быстрых и более-менее стабильно работающим, однако при повороте лица относительно горизонтали больше чем на 30 градусов он не находит объект. В составе библиотеки можно найти уже сгенерированные и настроенные классификаторы, которые можно использовать. Также библиотека предоставляет возможность поиска объекта по шаблону соответствия (Template matching). Шаблон соответствия -- метод, используемый, чтобы найти изображение меньшего размера в большем. Поиск можно приблизительно представить следующим образом: изображение шаблона последовательно накладывается на исходное изображение и между ними вычисляется корреляция, результат которой заносится в результирующее изображение. Таким образом можно обнаружить лицо, используя шаблонное совпадение.

Трекинг лица разделяется на несколько этапов. Первый -- подготовительный, получаем доступ к видео потоку. Библиотека предоставляет удобный функционал, который позволяет реализовать данную задачу всего в несколько строк. После того, как получили доступ к видео, необходимо каждый раз захватывать кадр из потока и обрабатывать его, что было представлено в листинге 1 -- метод getFrame. Для распознавания объектов OpenCV требует, чтобы изображение было в градациях серого, поэтому у каждого кадра обязательно изменяем цветность, метод getGrayFrame из листинга 1. На следующем этапе необходимо загрузить классификаторы Хаара. В OpenCV есть соответствующий класс для работы с этими классификаторами, который называется CascadeClassifier. Библиотека предоставляет набор своих классификаторов. По сути, классификатор является большим xml файлом (около 35тыс строк) с набором необходимых значений. Для его загрузки используется метод load класса CascadeClassifier. Далее для поиска лиц используется вызов метода detectMultiScale все того же класса. Данный метод возвращает массив прямоугольников с найденными лицами. Для однозначного определения лица будем брать наибольший прямоугольник. Теперь есть координаты прямоугольника, описанного вокруг лица, которые можно отслеживать.

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

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

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

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

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

Рисунок 1 - Алгоритм трекинга лица

while(true)

{

получить кадр; if(найдены углы)

повернуть область кадра if(не найдены лица)

{

}

else

{

найти лицо во всем кадре найдены углы = false

выключить монитор если необходимо

включить монитор если необходимо находим лицо в области кадра

Находим глаза и определяем угол наклона головы if(найдены углы) находим лицо в области кадра

if (не нашли лицо в заданной области)

найти лицо по заранее сохраненному шаблону

}

Отобразить рамку вокруг найденного лица Выход из цикла если необходимо

}

Листинг 2 - Псевдокод алгоритма трекинга лица

Теперь для разработки имеется алгоритм и псевдокод, по которым можно вести разработку части программы, отвечающую за трекинг лица. Как было указано в листинге 1 этим будет заниматься метод detectFace. В листинге 3 представлена его реализация.

Rect detectFace(Mat &grayscaleFrame, Mat &captureFrame )

{

if(foundAngles)

warpAffine(grayscaleFrame(faceROI), grayscaleFrame(faceROI), r, Size(grayscaleFrame(faceROI).cols, grayscaleFrame(faceROI).rows));

if(!detect) //Если лицо не найдено

{

else

{

detectFaces(grayscaleFrame); //Пытаемся найти лицо во всем кадре

foundAngles = false; //Снимаем флаг того, что есть углы поворота лица по глазам offMonitorIfNeed(); }

onMonitorIfNeed(); detectFaceAroundRoi(grayscaleFrame);

detectEyes(grayscaleFrame); //Находим глаза и определяем угол наклона головы if(foundAngles) //Если нашли угол, то пытаемся снова найти лицо, но с уже повернутой

//областью лица detectFaceAroundRoi(grayscaleFrame);

if (m_templateMatchingRunning)

{

log("try detect using template matching \n"); detectFaceTemplateMatching(grayscaleFrame); //Пытаемся найти лицо по шаблону

}

}

Rect faceRect = rectangleFace();

drawRectagle(captureFrame, faceRect); //Обводим область лица на цветном кадре прямоугольником

return faceRect;

}

Листинг 3 - Реализация трекинга лица

Поясним некоторые моменты. Метод возвращает структуру Rect, в которой содержаться координаты верхнего левого угла, а также высота и ширина прямоугольника. В качестве параметров метод принимает две матрица изображения из видео потока. Первая grayscaleFrame - кадр в градациях серого, вторая captureFrame - цветной кадр для пользователя. Для уточнения поясним, что метод warpAffine является стандартным методом OpenCV. Этот метод реализует поворот матрицы на заданный угол.

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

Рисунок 2 - Захваченный кадр из видеопотока

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

Рисунок 3 - Программа обнаружила лицо

Далее запоминаем координаты области, в которой будем определять лицо, а также создаем шаблон, по которому будем искать в случае, если не найдем лицо в данной области. Допустим, если потеряли лицо при повороте, то будем искать по шаблону (рисунок 4).

Рисунок 4 - Шаблон поиска

На рисунке 5 слева можно увидеть результат применения шаблона -- корреляцию между шаблоном и изображением. Теперь, на основе совпадения, по координатам шаблона определяем область лица и обводим его для наглядности черной рамкой (рисунок 5 справа).

Рисунок 5 - Результат применения шаблона

Слева - корреляция между шаблоном и кадром, справа - найденное лицо.

Конец первой итерации цикла. Обновляем позицию лица в цветном кадре (рисунок 6).

Рисунок 6 - Итоговое изображение после первого цикла программы

Переходим на начало следующей итерации. Так как теперь знаем область расположения лица, то, чтобы не сканировать весь кадр, начинаем поиск в этой области (рисунок 7 справа).

Рисунок 7 - Выбор области поиска на второй итерации цикла

Слева - кадр на новой итерации, справа - поиск в заранее известной области

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

Рисунок 8 - Линия между найденными глазами

Если повернуть голову, то найдем угол и повернем картинку (рисунок 9).

Рисунок 9 - Поворот области на заданный угол

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

Рисунок 10 - Обработанное изображение для корректного трекинга лица

Нашли лицо - значит, теперь есть его координаты. Сопоставив эти координаты с цветным кадром, получим следующее изображение, представленное на рисунке 11.

Рисунок 11 - Изображение которое видит пользователь

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

2.6 Трекинг объекта по цвету

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

Пусть метод, который будет осуществлять логику работы с трекингом объекта и перемещением курсора, будет называться detectColorObject (листинг 1).

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

Теперь все готово для трекинга объекта, ее реализацию поместим в метод detectObj. Для наглядности в листинге 4 представлено тело метода detectColorObject.

void detectColorObject(Mat& bgrImage, Mat& depthMap, Rect& excludeROI)

{

inRange(bgrImage, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), depthMap); depthMap(excludeROI) = Scalar (0);

detectObj(depthMap, bgrImage.clone());

}

Листинг 4 - Тело метода отвечающего за трекинг объекта по цвету

Перейдем непосредственно к созданию трекинга объекта. Чтобы обнаружить объект по цвету в OpenCV существует функция findContours, которая находит контуры объектов. Одним из ее аргументов является кадр depthMap в цветовом диапазоне, полученном в методе inRange (листинг 4). После анализа кадра метод findContours возвращает массив найденных контуров. Для упрощения работы будем выбирать самый большой контур. У каждого контура имеется набор координат, по ним вычисляем среднюю точку. Смещение этой точки будет коррелировать со смещением курсора мыши. Собственно для смещения нужно будет вызывать системные функции. Таким образом, получилась относительно простая реализация задуманного алгоритма. Перейдем к выбору цвета. В листинге 4 в метод inRange передаются скалярные величины из переменных iLowH, iLowS, iLowV, iHighH, iHighS и iHighV. От них зависит цветовой диапазон поиска. Собственно они и будут изменяться в процессе подгонки цвета пользователем. Для их изменения были созданы методы scanMode и colorControlPanel (листинг 1). Первый метод будет изменять величины самостоятельно, а второй будет давать пользователю подгонять самому. Реализация метода scanMode представлена в листинге 5.

void scanMode()

{

namedWindow(SCAN_NAME_WINDOW, 1);

Rect roiScan(0,0,bgrImage.cols/2, bgrImage.rows/2) ;

initHandColor(bgrImage(roiScan));

}

Листинг 5 - Реализация вспомогательного окна

В первой строчке создается новое окно, в которое помещается четверть захваченного кадра (вторая строчка создания объекта roiScan класса Rect). Далее в методе initHandColor сканируем цвет объекта, и берем усредненный. Метод colorControlPanel спроектирован аналогично за исключением того, что вместо усредненного цвета берутся данные, контролируемые пользователем с помощью ползунков.

Для наглядности продемонстрируем работу реализации алгоритма цветового трекинга объекта. На рисунке 12 продемонстрирован захваченный цветной кадр.

Рисунок 12 - Первый захваченный кадр из видеопотока

Далее этот кадр трансформируется в цветовое пространство HSV, потом в черно-белый вариант, что показано на рисунке 13.

Рисунок 13 - Кадр в черно-белом варианте

Для того чтобы начать отслеживать объект по цвету нужно этот цвет указать программе. Как уже было ранее сказано, в программе имеется два способа указать цвет. Воспользуемся автоматическим. Его можно вызвать по нажатию на клавишу «Пробел». После нажатия появляются два окна. В первом окне для запоминания цвета нужно поместить объект так, чтобы зеленые квадраты были нацелены на него (рисунок 14). В данном примере будет осуществляться трекинг желтой карточки.

Рисунок 14 - Сканирование цвета объекта

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

Рисунок 15 - Бинарное отображение

Далее OpenCV определяет координаты контура. Этот контур можно визуализировать, что представлено на рисунке 16. Потом, зная контур, вычисляется средняя точка и производится корреляция этих координат с координатами мыши.

Рисунок 16 - Итоговое изображение

Так происходит выбор цвета объекта и его трекинг на примере карточки желтого цвета. Но в этом примере не показано наглядно удаление области лица перед поиском контура. Продемонстрируем это на примере трекинга руки. Для начала зададим цвет (рисунок 17).

Рисунок 17 - Сканирование цвета руки

Теперь получаем следующее двоичное изображение, представленное на рисунке 18.

Рисунок 18 - Двоичное изображение

Как видно на рисунке 18, по выбранному цвету будет осуществляться трекинг не только руки, но и лица, тогда как трекинг лица необходим для других целей. Область лица удаляется (рисунок 19).

Рисунок 19 - Двоичное изображение с удаленной областью лица

Теперь будет отслеживаться только рука. В итоге получаем изображение как на рисунке 20.

Рисунок 20 - Результирующее изображение

Перейдем ко второму способу выбора цвета. Для вызова окон ручного подбора цвета необходимо нажать клавишу «С». Для примера снова возьмем трекинг желтой карточки, но пусть изначально цвет не подобран, что отображено некорректным контуром на рисунке 21.

Рисунок 21 - Изображение с некорректной настройкой цвета

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

Рисунок 22 - Двоичное изображение

Второе окно будет содержать в себе ползунки с настройками каналов HSV. Для каждого из трех каналов будет задаваться нижняя и верхняя цветовая граница (рисунок 23).

Рисунок 23 - Окно с текущими настройками поиска цвета

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

Рисунок 24 - Окно с перенастроенными уровнями цвета

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

Рисунок 25 - Двоичное изображение

В итоге результирующее изображение будет таким как на рисунке 26.

Рисунок 26 - Результирующее изображение

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

Реализация программы

Класс main.cpp

#include "mainHeader.h"

#include "FaceDetectorHeader.h"

#include "ObjectColorDetectorHeader.h"

#include "InitializerHeader.h"

#include "FrameHelperHeader.h"

int wk = 0;

Rect excludedFaceROI;

int main()

{

connectToVideo(); //Подключаемся к любой доступной камере initControlWindows(); //Инициализация окна контроля loadCascades(); //Инициализация каскадов для трекинга лица

clockInit(); //Инициализация таймеров для отключения/включения монитора

while(true)

{

getFrame(cap, bgrImage); //Получаем кадр из видеокамеры

depthMap = getFrameForObjectTracking(bgrImage); //Обрабатываем кадр для трекинга объекта grayscaleFrame = getGrayFrame(bgrImage); //Обрабатываем полученный кадр для трекинга лица excludedFaceROI = detectFace(grayscaleFrame, bgrImage); //Поиск лица, отключение монитора detectColorObject(bgrImage, depthMap, excludedFaceROI); //Трекинг объекта

wk = waitKey( 20 ); //Нажатие клавиши if( wk == 27 ) //ESC

{

break; //Выход

}

else if (wk == 32 )//Space

{

scanMode();//Запуск автоматичесского сканирования цвета

}

else if (wk == 67)//C

{

colorControlPanel();//Запуск ручного скинрования цвета

}

else if(wk == 86)//V

{

destroyScanModeWindow();//Закрытие окна автоматического сканирования

}

}

waitKey(); return 0;

}

Класс FaceDetector.cpp

#include "FaceDetectorHeader.h"

#include "SysstemCallerHelperHeader.h"

const char* FRONT_CASCADE_NAME = "haarcascade_frontalface_alt_tree.xml"; const char* PROFILE_CASCADE_NAME = "haarcascade_profileface.xml";

const char* EYE_CASCADE_NAME = "haarcascade_eye.xml";

//HWND hwnd = nullptr;

CascadeClassifier face_cascade; //Каскад для определения лица CascadeClassifier eye_cascade; //Каскад для определения глаз

CascadeClassifier faceProfile_cascade; //Каскад для определения лица в профиль

VideoCapture captureDevice; //Камера

vector<Rect> faces; //Массив найденных лиц vector<Rect> eyes; //Массив найденных глаз

Mat captureFrame; //Матрица цветного кадра Mat grayscaleFrame;

Mat faceTemplate; //Матрица шаблона

Mat m_matchingResult; //Матрица шаблона Mat r ; //Матрица поворота

Rect face; //Область лица

Rect faceROI; //"Область интересов" вокруг области лица Rect eyesROI; //"Область интересов" вокруг области глаз

Point m_facePosition = NULL; //Координаты центра лица

boolean detect = false; //Флаг - нашли лицо или нет boolean monitorIsOFF = false; //Флаг - монитор выключен boolean foundAngles = false; //Флаг - найдены углы поворта boolean logIsON = false; //Флаг - логирование включено

bool m_templateMatchingRunning = false; //Флаг - поиск по шаблону

//Число мс для нахождения по шаблону int64 m_templateMatchingStartTime = 0; int64 m_templateMatchingCurrentTime = 0;

double m_templateMatchingMaxDuration = 3; //Максимальное время поиска по шаблону double m_scale = 1; //Масштаб

float angle = 0; //Угол поворота головы

//Таймеры

const double TICK_FREQUENCY = getTickFrequency(); clock_t cl = NULL ;

clock_t clClose = NULL;

void log(const char *message)

{

if(logIsON)

printf(message);

}

Rect calculateROI(const Rect &inputRect, const Rect &frameSize)

{

Rect outputRect;

outputRect.width = inputRect.width * 2; outputRect.height = inputRect.height * 2;

outputRect.x = inputRect.x - inputRect.width / 2; outputRect.y = inputRect.y - inputRect.height / 2;

if (outputRect.x < frameSize.x) { outputRect.width += outputRect.x; outputRect.x = frameSize.x;

}

if (outputRect.y < frameSize.y) { outputRect.height += outputRect.y; outputRect.y = frameSize.y;

}

if (outputRect.x + outputRect.width > frameSize.width) { outputRect.width = frameSize.width - outputRect.x;

}

if (outputRect.y + outputRect.height > frameSize.height) { outputRect.height = frameSize.height - outputRect.y;

}

return outputRect;

}

Point centerOfRect(const Rect &rect)

{

return Point(rect.x + rect.width / 2, rect.y + rect.height / 2);

}

Rect biggestFace(vector<Rect> &faces)

{

assert(!faces.empty());

Rect *biggest = &faces[0]; for (auto &face : faces) {

if (face.area() < biggest->area()) biggest = &face;

}

return *biggest;

}

Mat getFaceTemplate(const Mat &frame, Rect face)

{

face.x += face.width / 4; face.y += face.height / 4; face.width /= 2;

face.height /= 2;

Mat faceTemplate = frame(face).clone(); return faceTemplate;

}

void detectFaces(Mat &frame)

{

log("try detect in whole frame \n");

face_cascade.detectMultiScale(frame, faces, 1.1, 3,0,//CV_HAAR_FIND_BIGGEST_OBJECT, Size(frame.rows / 5, frame.rows / 5),

Size(frame.rows * 2 / 3, frame.rows * 2 / 3));

if(faces.size()==0)

{

log("detect in whole frame frontal face is FAIL \n"); log("try detect in whole frame profile face \n");

faceProfile_cascade.detectMultiScale(frame, faces, 1.1, 3,0,//CV_HAAR_FIND_BIGGEST_OBJECT, Size(frame.rows / 5, frame.rows / 5),

Size(frame.rows * 2 / 3, frame.rows * 2 / 3));

}

if(faces.size()==0)

{

log("detect in whole frame profile face is FAIL \n"); return;

}

log("detect in whole frame is SUCCESS \n"); detect = true;

face = biggestFace(faces); //faces[0]; faceTemplate = getFaceTemplate(frame, face);

faceROI = calculateROI(face, Rect(0, 0, frame.cols, frame.rows)); m_facePosition = centerOfRect(face);

}

void detectFaceAroundRoi(Mat &frame)

{

log("detect around ROI");

face_cascade.detectMultiScale(frame(faceROI), faces, 1.1, 3,0,// CV_HAAR_FIND_BIGGEST_OBJECT, Size(face.width * 8 / 10, face.height * 8 / 10),

Size(face.width * 12 / 10, face.width * 12 / 10));

if(faces.size()==0)

{

log("detect in ROI frontal face is FAIL \n"); log("try detect in ROI profile face \n");

faceProfile_cascade.detectMultiScale(frame(faceROI), faces, 1.1, 3,0,//CV_HAAR_FIND_BIGGEST_OBJECT,

Size(face.width * 8 / 10, face.height * 8 / 10),

Size(face.width * 12 / 10, face.width * 12 / 10));

}

if(faces.size()==0)

{

log("detect around ROI is FAIL \n");

log("need try detect using matching \n"); detect = false; m_templateMatchingRunning = true;

if (m_templateMatchingStartTime == 0) m_templateMatchingStartTime = getTickCount();

return;

}

log("detect around ROI is SUCCESS \n"); m_templateMatchingRunning = false;

m_templateMatchingCurrentTime = m_templateMatchingStartTime = 0; face = biggestFace(faces); //faces[0];

face.x += faceROI.x; face.y += faceROI.y;

faceTemplate = getFaceTemplate(frame, face);

faceROI = calculateROI(face, Rect(0, 0, frame.cols, frame.rows)); m_facePosition = centerOfRect(face);

}

void detectFaceTemplateMatching(Mat &frame)

{

m_templateMatchingCurrentTime = getTickCount();

double duration = (double)(m_templateMatchingCurrentTime - m_templateMatchingStartTime)/ TICK_FREQUENCY;

if (duration > m_templateMatchingMaxDuration) { detect = false;

m_templateMatchingRunning = false;

m_templateMatchingStartTime = m_templateMatchingCurrentTime = 0;

}

matchTemplate(frame(faceROI), faceTemplate, m_matchingResult, CV_TM_SQDIFF_NORMED);

//imshow("matchTemplate", faceTemplate); double min, max;

Point minLoc, maxLoc;

minMaxLoc(m_matchingResult, &min, &max, &minLoc, &maxLoc); normalize(m_matchingResult, m_matchingResult, 0, 1, NORM_MINMAX, -1, Mat());

//imshow("m_matchingResult", m_matchingResult); minLoc.x += faceROI.x;

minLoc.y += faceROI.y;

face = Rect(minLoc.x, minLoc.y, faceTemplate.cols, faceTemplate.rows); face = calculateROI(face, Rect(0, 0, frame.cols, frame.rows));

faceTemplate = getFaceTemplate(frame, face);

faceROI = calculateROI(face, Rect(0, 0, frame.cols, frame.rows));

m_facePosition = centerOfRect(face);

}

void detectEyes(Mat &frame)

{

eyesROI = calculateROI(Rect(face.x,face.y,face.width,face.height/2), Rect(0,0,frame.cols,frame.rows));

//imshow("eyesROI", frame(eyesROI)); log("try detect eyes.. \n");

eye_cascade.detectMultiScale( frame(eyesROI), eyes, 1.1, 2, 0 |CV_HAAR_SCALE_IMAGE, Size(30, 30) );

if(eyes.size()==2)

{

log("detect eyes is SUCCESS \n");

Point ept1 (eyesROI.x + eyes[0].x + eyes[0].width*0.5,eyesROI.y + eyes[0].y + eyes[0].width*0.5) ;

Point ept2 (eyesROI.x + eyes[1].x + eyes[1].width*0.5,eyesROI.y + eyes[1].y + eyes[1].width*0.5) ;

if(ept1.x>ept2.x)

{

Point buf = ept1; ept1 = ept2; ept2 = buf;

}

float distanceX = (float) (eyes[1].x ) - (float) eyes[0].x; float distanceY = (float) (eyes[1].y) - (float) eyes[0].y; angle = atan2(distanceY, distanceX) * 180 / CV_PI ;

if(-60<angle && angle<60 )

{

log("angle of rotate is");

//cout<<angle<<" \n";

Point2f pt(grayscaleFrame (faceROI).cols/2.,grayscaleFrame(faceROI).rows/2.); r = getRotationMatrix2D(pt, angle, 1.0);

warpAffine(grayscaleFrame(faceROI), grayscaleFrame(faceROI), r, Size(grayscaleFrame(faceROI).cols, grayscaleFrame(faceROI).rows));

foundAngles = true;

}

else

{

}

}

}

//line(captureFrame, ept1, ept2, cvScalar(0, 255, 0, 0), 1, 8, 0);

line(grayscaleFrame, ept1, ept2, cvScalar(0, 255, 0, 0), 1, 8, 0);

log("detect eyes is FAIL \n"); return;

Rect rectangleFace()

{

Rect faceRect = face;

faceRect.x = (int)(faceRect.x / m_scale); faceRect.y = (int)(faceRect.y / m_scale); faceRect.width = (int)(faceRect.width / m_scale); faceRect.height = (int)(faceRect.height / m_scale); return faceRect;

}

void drawRectagle(Mat &frame, Rect &rectagle)

{

rectangle(frame, rectagle, cvScalar(0, 255, 0, 0), 1, 8, 0);

}

Rect detectFace(Mat &grayscaleFrame, Mat &captureFrame )

{

if(foundAngles) //Если были найдены углы поворота изображения в области лица на предыдущем шаге цикла, то поворочиваем изображение

warpAffine(grayscaleFrame(faceROI), grayscaleFrame(faceROI), r, Size(grayscaleFrame(faceROI).cols, grayscaleFrame(faceROI).rows)); //Поворот области лица на всем кадре на найденную в предыдущем шаге цикла матрицу поворота

if(!detect) //Если лицо не найдено

{

detectFaces(grayscaleFrame); //Пытаемся найти лицо во всем кадре

foundAngles = false; //Снимаем флаг того, что есть углы поворота лица по глазам offMonitorIfNeed(); //Если на протяжении заданного времени лицо так и небыло найдено, то

выключаем монитор

}

else

{

включаем монитор

onMonitorIfNeed(); //Если на протяжении заданного времени лицо стабильно находилось, то

detectFaceAroundRoi(grayscaleFrame); //Находим лицо не во всем кадре, а только в небольшой

области, где предположительно оно находится

detectEyes(grayscaleFrame); //Находим глаза и определяем угол наклона головы

if(foundAngles) //Если нашли угол, то пытаемся снова найти лицо, но с уже повернутой областью лица

detectFaceAroundRoi(grayscaleFrame);

if (m_templateMatchingRunning) //Флаг того что не нашли лицо в заданной области, попытаемся найти его по заранее сохраненному шаблону

{

сохраненному шаблону

}

log("try detect using template matching \n"); detectFaceTemplateMatching(grayscaleFrame); //Пытаемся найти лицо по заранее

}

//drawRectagle(grayscaleFrame, rectangleFace()); //Обводим область лица на ч/б кадре прямоугольником Rect faceRect = rectangleFace();

drawRectagle(captureFrame, faceRect); //Обводим область лица на цветном кадре прямоугольником

//circle(captureFrame, m_facePosition, 30, Scalar(0, 255, 0)); //Либо обводим окружностью

//imshow("grayscale", grayscaleFrame); //Покажем ч/б кадр

//imshow("outputCapture", captureFrame); //Покажем цветной кадр

return faceRect;

}

Класс ObjecColorDetector.cpp

#include "ObjectColorDetectorHeader.h"

#include "SysstemCallerHelperHeader.h"

Mat depthMap; VideoCapture cap; Mat bgrImage;

const char* CONTROL_NAME_WINDOW = "Control"; const char* SCAN_NAME_WINDOW = "Scan"; const char* DEPTH_NAME_WINDOW = "Depth";

const int DEFAULT_DELAY_BEFORE_DESTROY = 7000;

vector <Rect> roi; Point upper_corner; Point lower_corner; Scalar color;

int border_thickness=2;

int iLowH = 93; int iHighH = 113; int iLowS = 239; int iHighS = 259; int iLowV = 243; int iHighV = 263;

boolean notInitControlPanel = true; boolean notInitScanModePanel = true;

map < char*, int*> trackBarSettings;

int findBiggestContour(vector<vector<Point> > contours)

{

int indexOfBiggestContour = -1; int sizeOfBiggestContour = 0;

for (int i = 0; i < contours.size(); i++){ if(contours[i].size() > sizeOfBiggestContour)

{

sizeOfBiggestContour = contours[i].size(); indexOfBiggestContour = i;

}

}

return indexOfBiggestContour;

}

Rect calcRect(Point u_corner, Point l_corner, Mat src)

{

upper_corner = u_corner; lower_corner=l_corner; color=Scalar(0,255,0); border_thickness=2;

return Rect(u_corner.x, u_corner.y, l_corner.x-u_corner.x,l_corner.y-u_corner.y);

}

void findAverage(Mat &frame, vector <Rect> roi)

{

Vector<Scalar> means (roi.size());

for(int i=0; i< roi.size(); i++)

{

means[i] = mean(frame(roi[i]));

}

Scalar medium(0,0,0);

for(int i=0; i< means.size(); i++)

{

medium[0] += means[i][0];

medium[1] += means[i][1];

medium[2] += means[i][2];

}

medium[0] /= means.size(); medium[1] /= means.size(); medium[2] /= means.size();

int valueRange = 13;

iLowH = (int)medium[0] - valueRange; iHighH = (int)medium[0] + valueRange;

iLowS = (int)medium[1] - valueRange; iHighS = (int)medium[1] + valueRange;

iLowV = (int)medium[2] - valueRange; iHighV = (int)medium[2] + valueRange;

}

void initHandColor(Mat &frame)

{

int square_len=20;

//roi.push_back(calcRect(Point(frame.cols/3, frame.rows/6),Point(frame.cols/3+square_len,frame.rows/6+square_len),frame));

//roi.push_back(calcRect(Point(frame.cols/4, frame.rows/2),Point(frame.cols/4+square_len,frame.rows/2+square_len),frame));

//roi.push_back(calcRect(Point(frame.cols/3, frame.rows/1.5),Point(frame.cols/3+square_len,frame.rows/1.5+square_len),frame));

roi.push_back(calcRect(Point(frame.cols/2, frame.rows/2),Point(frame.cols/2+square_len,frame.rows/2+square_len),frame));

roi.push_back(calcRect(Point(frame.cols/2.5, frame.rows/2.5),Point(frame.cols/2.5+square_len,frame.rows/2.5+square_len),frame));

roi.push_back(calcRect(Point(frame.cols/2, frame.rows/1.5),Point(frame.cols/2+square_len,frame.rows/1.5+square_len),frame));

//roi.push_back(calcRect(Point(frame.cols/2.5, frame.rows/1.8),Point(frame.cols/2.5+square_len,frame.rows/1.8+square_len),frame));

findAverage(frame, roi); for(int i=0; i<roi.size(); i++)

{

rectangle(frame, roi[i], color, border_thickness);

}

imshow(SCAN_NAME_WINDOW, frame);

}

void detectObj(Mat& mask, Mat& bgr)

{

int largest_area=0;

int largest_contour_index=0; Rect bounding_rect; vector<vector<Point>> contours; vector<Vec4i> hierarchy;

Mat frm ; Rect roi; roi.x = 0;

roi.y = 0;

roi.width = mask.cols/2; roi.height = mask.rows/2; mask.copyTo(frm);

findContours(frm, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); int indx = findBiggestContour(contours);

vector<vector<Point> >hull( contours.size() ); double x=0 ; double y=0;

if(indx != -1 )

{

convexHull( Mat(contours[indx]), hull[indx], false );

for(int i=0; i<contours[indx].size();i++)

{

x += contours[indx][i].x; y += contours[indx][i].y;

}

x /= contours[indx].size(); y /= contours[indx].size();

//printf("x= "); cout << x; printf(" y= "); cout << y;printf("\n");

}

moveCursor(x ,y);

rectangle(bgr, Rect((int)x-30, (int)y-30, 60, 60 ), cvScalar(0, 255, 0, 0));

drawContours(bgr, hull, indx, Scalar(0,250,0), 2 , 8, vector<Vec4i>(), 0, Point()); if(!notInitControlPanel || !notInitScanModePanel)

{

imshow(DEPTH_NAME_WINDOW, mask);

}

imshow("bgr", bgr);

}

void detectColorObject(Mat& bgrImage, Mat& depthMap, Rect& excludeROI)

{

Filter

inRange(bgrImage, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), depthMap); //Color

//printf("iLowH= "); cout << iLowH; printf(" iLowS= "); cout << iLowS; printf("iLowV= "); cout <<

iLowV; printf("\n");

//printf("iHighH= "); cout << iHighH; printf(" iHighS= "); cout << iHighS; printf("iHighV= "); cout

<< iHighV; printf("\n");

depthMap(excludeROI) = Scalar (0); detectObj(depthMap, bgrImage.clone());

}

void destroyScanModeWindow()

{

destroyWindow(SCAN_NAME_WINDOW); notInitScanModePanel = true; if(notInitControlPanel)

{

destroyWindow(DEPTH_NAME_WINDOW);

}

}

void scanMode()

{

namedWindow(SCAN_NAME_WINDOW, 1);

Rect roiScan(0,0,bgrImage.cols/2, bgrImage.rows/2) ; initHandColor(bgrImage(roiScan)); notInitScanModePanel = false;

}

void initControlPanel()

{

if(notInitControlPanel)

{

trackBarSettings["LowH"] = &iLowH; trackBarSettings["HighH"] = &iHighH; trackBarSettings["LowS"] = &iLowS; trackBarSettings["HighS"] = &iHighS; trackBarSettings["LowV"] = &iLowV; trackBarSettings["HighV"] = &iHighV; notInitControlPanel = false;

}

}

void destroyControlPanelWindow()

{

if(!notInitControlPanel )

{

destroyWindow(CONTROL_NAME_WINDOW); notInitControlPanel = true; if(notInitScanModePanel)

{

destroyWindow(DEPTH_NAME_WINDOW);

}

}

}

void colorControlPanel()

{

if(notInitControlPanel)

{

initControlPanel();

namedWindow(CONTROL_NAME_WINDOW, CV_WINDOW_AUTOSIZE); //create a window called "Control"

iterator++)

}

else

{

}

for(auto iterator = trackBarSettings.begin(); iterator != trackBarSettings.end();

{

cvCreateTrackbar((*iterator).first, CONTROL_NAME_WINDOW, (*iterator).second, 255);

}

destroyControlPanelWindow();

}

Класс FrameHelper.cpp

#include "FrameHelperHeader.h"

Mat getFrame(VideoCapture &captureDevice, Mat &captureFrame)

{

captureDevice>>captureFrame; flip(captureFrame,captureFrame,1); return captureFrame;

}

Mat getFrameForObjectTracking(Mat &captureFrame)

{

Mat frame;

cvtColor(captureFrame, frame, CV_RGBA2GRAY); equalizeHist(frame, frame);

return frame;

}

//Получить ч/б кадр

Mat getGrayFrame(Mat &captureFrame)

{

Mat grayFrame;

cvtColor(captureFrame, grayFrame, CV_RGBA2GRAY); equalizeHist(grayFrame, grayFrame);

return grayFrame;

}

Класс Initializer.cpp

#include "InitializerHeader.h"

#include "FaceDetectorHeader.h"

#include "ObjectColorDetectorHeader.h" HWND hwnd = nullptr;

int initVideo(HWND &hwnd, VideoCapture &captureDevice)

{

hwnd = GetDesktopWindow(); printf("\nCheck access to camera ..."); if(!captureDevice.open(0))

{

printf("\nNot access to camera \n"); return 0;

}

printf(" success \n");

//namedWindow("outputCapture", 1);

return 1;

}

void initControlWindows()

{

//namedWindow("depth", 1);

namedWindow("bgr", 1);

}

int connectToVideo()

{

if(!initVideo(hwnd, cap)) //Инициализация видео с веб камеры

{

printf("\nNo find camera\n"); printf("\nExit with code -1 \n"); system ("pause");

return -1;

}

}

int loadCascade(CascadeClassifier &cascade,const String &name)

{

try

{

cascade.load(name); if(cascade.empty())

{

return 0;

}

}

catch(Exception e)

{

printf(e.what());

system ("pause");

}

return 1;

}

int cascadeLoadError()

{

printf("\nNo find cascades\n"); printf("\nExit with code -1 \n"); system ("pause");

return -1;

}

void loadCascades()

{

if(!loadCascade(face_cascade, FRONT_CASCADE_NAME)

&& !loadCascade(faceProfile_cascade, PROFILE_CASCADE_NAME)

&& !loadCascade(eye_cascade, EYE_CASCADE_NAME)) //Загрузка каскада Хаара

{

cascadeLoadError();

}

}

void clockInit()

{

cl = clock(); clClose = clock();

}

Класс SysstemCallerHelper.cpp

#include "SysstemCallerHelperHeader.h"

#include "FaceDetectorHeader.h"

#include "ObjectColorDetectorHeader.h"

double oldX = 0; double oldY = 0;

void offMonitorIfNeed()

{

if(!monitorIsOFF && clock()-clClose>15000)

{

log("monitor Off \n");

SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, 2);

monitorIsOFF = true; clClose = 0;

}

cl = clock();

}

void onMonitorIfNeed()

{

if(monitorIsOFF && clock()-cl>500)

{

log("monitor On \n");

SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, -1);

monitorIsOFF = false; cl = 0;

}

clClose = clock();

}

void moveCursor(double x, double y)

{

if(!notInitControlPanel || !notInitScanModePanel)

{

return;

}

if(abs(x-oldX) < 15)

{

x = oldX;

}

if(abs(y-oldY) < 15)

{

y = oldY;

}

if(x != 0 && y != 0)

{

SetCursorPos(x ,y);

}

}

Хедер FaceDetectorHeader.cpp

#pragma once

#ifndef FACE_DETECTOR

#define FACE_DETECTOR

#include "mainHeader.h"

extern cv::Mat grayscaleFrame; //Матрица ч/б кадра extern const char* FRONT_CASCADE_NAME ;

extern const char* PROFILE_CASCADE_NAME ; extern const char* EYE_CASCADE_NAME;

extern cv::CascadeClassifier face_cascade; //Каскад для определения лица extern cv::CascadeClassifier eye_cascade; //Каскад для определения глаз

extern cv::CascadeClassifier faceProfile_cascade; //Каскад для определения лица в профиль extern clock_t cl ;

extern clock_t clClose; extern boolean monitorIsOFF; void loadCascades();

void log(const char *message);

Rect detectFace(Mat &grayscaleFrame, Mat &captureFrame );

#endif

Класс FrameHelperHeader.cpp

#pragma once

#ifndef FRAME_HELPER

#define FRAME_HELPER

#include "mainHeader.h"

cv::Mat getFrame(VideoCapture &captureDevice,cv::Mat &captureFrame); cv::Mat getFrameForObjectTracking(cv::Mat &captureFrame);

cv::Mat getGrayFrame(Mat &captureFrame);

#endif

Класс InitializerHeader.cpp

#pragma once

#ifndef INITIALIZER

#define INITIALIZER

#include "mainHeader.h" extern HWND hwnd;

int initVideo(HWND &hwnd, cv::VideoCapture &captureDevice); int connectToVideo();

void initControlWindows(); void loadCascades();

void clockInit();

#endif

Класс mainHeader.cpp

#pragma once

#ifndef MAIN

#define MAIN

#include <opencv2/highgui/highgui.hpp>

#include <opencv2/imgproc/imgproc.hpp>

#include <ctime>

#include <cstdlib>

#include <stdio.h>

#include <cv.h>

#include <iostream>

#include <opencv2/objdetect/objdetect.hpp>

#include <windows.h>

#pragma comment(lib, "User32.lib")

#pragma comment(lib, "GDI32.lib")

#pragma comment(lib, "Advapi32.lib")

using namespace std; using namespace cv;

#endif

Класс ObjectColorDetectorHeader.cpp

#pragma once

#ifndef COLOR_DETECTOR

#define COLOR_DETECTOR

#include "mainHeader.h" extern Mat depthMap;

extern cv::VideoCapture cap; extern Mat bgrImage;

extern boolean notInitControlPanel; extern boolean notInitScanModePanel;

void detectColorObject(Mat& bgrImage, Mat& depthMap, Rect& excludeROI); void initHandColor(cv::Mat &frame);

void scanMode();

void colorControlPanel(); void destroyScanModeWindow();

#endif

ЗАКЛЮЧЕНИЕ

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


Подобные документы

  • Метод главных компонент. Процесс распознавания. Ковариационная матрица, диагональная матрица собственных чисел. Использовании метрики Махаланобиса и Гауссовского распределения для оценки близости изображений. Входные вектора. Библиотека OpenCV.

    статья [22,1 K], добавлен 29.09.2008

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

    курсовая работа [669,9 K], добавлен 20.05.2017

  • OpenCV – библиотека компьютерного зрения с открытым исходным кодом, предоставляющая набор типов данных, функций и численных алгоритмов для обработки изображений. Ее реализация на C/C++. Цели использования технологии. Основные модули библиотек 1-3.

    презентация [121,8 K], добавлен 14.12.2013

  • Задачи компьютерного зрения. Анализ, разработка и реализация алгоритмов поиска и определения движения объекта, его свойств и характеристик. Алгоритмы поиска и обработки найденных областей движения. Метод коррекции. Нахождение объекта по цветовому диапазон

    статья [2,5 M], добавлен 29.09.2008

  • Оптико-электронная система идентификации объектов подвижного состава железнодорожного транспорта. Автоматический комплекс распознавания автомобильных номеров. Принципы и этапы работы систем оптического распознавания. Особенности реализации алгоритмов.

    дипломная работа [887,3 K], добавлен 26.11.2013

  • Методы предобработки изображений текстовых символов. Статистические распределения точек. Интегральные преобразования и структурный анализ. Реализация алгоритма распознавания букв. Анализ алгоритмов оптического распознавания символов. Сравнение с эталоном.

    курсовая работа [2,1 M], добавлен 20.09.2014

  • Обзор существующих алгоритмов для обнаружения лиц. Выравнивание лица с помощью разнообразных фильтров. Использование каскадного классификатора Хаара для поиска лиц на изображении. Распознавание лиц людей с использованием локальных бинарных шаблонов.

    дипломная работа [332,4 K], добавлен 30.09.2016

  • Процессы распознавания символов. Шаблонные и структурные алгоритмы распознавания. Процесс обработки поступающего документа. Обзор существующих приложений по оптическому распознаванию символов. Определение фиксированного шага и сегментация слов.

    дипломная работа [3,3 M], добавлен 11.02.2017

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

    дипломная работа [337,5 K], добавлен 24.01.2016

  • Основные категории изображений: растровые и векторные. Программы, работающие с растровыми изображениями. Инструменты для работы с обоими типами графики в программе Photoshop. Обзор современных программ обработки и просмотра графических изображений.

    курсовая работа [49,0 K], добавлен 20.09.2010

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.