Если нет денег на AXIS, или управляемая вебкамера своими, в меру кривыми, руками. Видеонаблюдение на основе пакета Motion
Краткая справка: Motion — Программа Motion способна контролировать сигнал, полученный с одной или нескольких видеокамер, и обнаруживать наличие изменений на картинке. На выходе получаем фотки в форматах jpeg, ppm или mpeg видеопоток, который может транслироваться в сеть или записываться в файл. При необходимости на указанный почтовый адрес может быть отослано сообщение с информацией о событии. Возможно выполнение любой предусмотренной пользователем команды или скрипта, поэтому реакция системы зависит только от твоей фантазии. Motion написан на языке Си, изначально разрабатывался для Linux, но может работать и в FreeBSD и Mac OS X. Поддерживаются все типы популярных сегодня видеокамер, подключаемых к компьютеру через USB порт, Video4Linux устройства и сетевые камеры. Драйверов для видеокамер проект Motion не предоставляет, поэтому прежде чем начинать настройку, убедись, что твоя камера видна операционке.
И так начнём. Я использую систему на базе amd64, всё что представлено ниже действия которыми у меня получилось запустить камеры в motion.
Будем ставить систему с помощью которой можно отслеживать изменения попадающие в поле деятельности нашей камеры.
1) Для начала убедимся что в нашей системе появилось видеоустройство.
Убедимся что система видит нашу web-камеру
ls -l /dev/
crw-rw—- 1 root video 81, 0 Авг 22 20:08 video0
2) Убедимся что присутствует модуль v4l
keiz@ekzorchik:~$ lsmod | grep v4l
v4l1_compat 17284 2 uvcvideo,videodev
keiz@ekzorchik:~$
3) Проверим информация о модуле v4l1_compat (так для общих сведений)
keiz@ekzorchik:~$ sudo modinfo v4l1_compat
filename: /lib/modules/2.6.26-2-amd64/kernel/drivers/media/video/v4l1-compat.ko
license: GPL
description: v4l(1) compatibility layer for v4l2 drivers.
author: Bill Dirks
depends:
vermagic: 2.6.26-2-amd64 SMP mod_unload modversions
parm: debug:enable debug messages (int)
4) Задействуем установку и пакетов
sudo apt-get install motion
keiz@ekzorchik:~$ whereis motion
motion: /usr/bin/motion /etc/motion /usr/share/man/man1/motion.1.gz
5) Открываем наш конфигурационный файл
sudo nano /etc/motion/motion.conf
И начинаем:
- определяем видеоустройство для захвата
videodevice /dev/video0
- Используем вход для видео, может иметь два значения:
8 = (для USB камер), для v4l — ставим 1
input = 8 (у меня Logitech C250)
- Устанавливаем количество захватываемых кадров в секунду
framate 25
- Указываем каталог куда будут складываться захваченные с видеокамеры файлы
target_dir /home/keiz/test_motion
- Имя файла для снимков и видео, в примере оставляем значение по умолчанию# %Y = год, %m = месяц, %d = день, %H = час, %M = минута, %S = секундаsnapshot_filename %v-%Y%m%d%H%M%S-snapshotjpeg_filename %v-%Y%m%d%H%M%S-%q
movie_filename %v-%Y%m%d%H%M%S
timelapse_filename %Y%m%d-timelapse
- Если используется карта видеозахвата или TV тюнер, при помощи параметра norm указываем стандарт. По умолчанию используется 0, то есть PAL. Возможны значения 1 — NTSC, 2 – SECAM и 3 PAL NC. Для TV тюнера также указываем частоту. По умолчанию frequency = 0.
- Чтобы Motion не переходил в режим демона и выводил отладочную информацию в консоль, используем флаг ‘–n’.$ motion –n
- В тестовом прогоне можно использовать sudo, а в повседневной жизни лучше разрешить запись в этот каталог членам группы (например, video) и себя, естественно, в нее включить.
- В состав Motion включен мини http-сервер, который позволяет просматривать в реальном времени картинку с камеры в окне браузера
webcam_port 0 -> т.е. htt-сервер отключен, чтобы он заработал нужно указать любой свободный порт(допустим 8081)webcam_localhost on -> определяет откуда на нашему http-серверу можно будет подключиться (только с локального компьютера)
webcam_localhost off -> если планируется заходить по сети
- webcam_quality 50 -> качество выводимых сервером jpeg изображений
webcam_motion on -> укажем. чтобы картинка менялась постоянно с частотой 1 кадр, а при движении — с частотой, указанной в параметре webcam_maxrate
webcam_limit 0 -> указывает максимальное количество изображений за соединение (по умолчанию 0, т.е. без ограничений)
- control_authenticaton username:password -> ограничиваем доступ на сервер, указываем логин и пароль для аутентификации.Теперь, набрав в консоли «motion -n», среди строк вывода ты должен увидеть «motion-httpd: waiting for data on port TCP 8080». Набираем в браузере адрес и получаем возможность указывать настройки для каждой камеры (thread), выбирая их и вводя нужные значения. При работе с несколькими камерами такой способ тебе, вероятно, покажется более удобным.
- rotate 0 -> снимать изображение в нормальном виде, без вращения (с помощью других параметров 90,180,270 можно вращать изображение) (Понадобиться если камеру расположили в перевернутом виде)
- По умолчанию при обнаружении движения образуется не только видеофайл, но и последовательность изображений. Параметром output_normal можно изменить такое поведение. Так при установке в first будет сохранено только первое изображение, best – лучшее, а отключить эту функцию можно, использовав off. Активация output_motion разрешит сохранять в снимке только пиксели, показывающие движущийся объект.
- в конфигурационном файле motion.conf функция записи захваченного видео отключена. Поэтому при необходимости измени значение ffmpeg_cap_new на on. Аналогично с output_motion, есть такой же параметр и для видео — ffmpeg_cap_motion, при активации которого в результирующий видеофайл будут сохранены пиксели, показывающие движущийся объект.
- За качество результирующего видео отвечают два параметра: ffmpeg_bps или ffmpeg_variable_bitrate. При настройке следует использовать лишь один из них. Качество лучше подбирать экспериментальным путем, исходя из мощности системы и возможностей камеры. Кодек задается при помощи ffmpeg_video_codec, по умолчанию используется mpeg4, но при необходимости можно использовать: mpeg1, msmpeg4, swf, flv или ffv1.
- (УДОБНАЯ ВЕЩЬ) В некоторых случаях полезной будет возможность периодической записи. Параметр ffmpeg_timelapse отвечает за период, в течение которого ведется запись информации в один видеофайл, затем будет создан новый. Возможные значения: daily (за день, по умолчанию), hourly, weekly-sunday, weekly-monday, monthly и manual. Например, чтобы запись на видео велась каждую секунду, устанавливаем «ffmpeg_timelapse 1». Если во время захвата с аналоговой камеры при перемещении объектов появляются искажения, установи ffmpeg_deinterlace в on.
- В файл, кроме собственно объекта, за которым следит камера, заносится и дополнительная информация, позволяющая определить время съемки. Эти данные настраиваются в секции Snapshots. Например, установка цифры в snapshot_interval позволит делать снимки с указанным периодом вне зависимости от обнаружения движения. Активация locate выделит на снимке движущийся объект. Текст, выводимый в левом и правом углах снимка, указывается соответственно в text_left и text_right. В настройках по умолчанию выводится дата и время, когда сделан снимок (формат strftime(3)). Если камер несколько, для удобства можно активировать text_left, где прописать что-то вроде «Camera 1».
- threshold позволяет указать количество пикселей, которые должны измениться для срабатывания детектора, а minimum_motion_frames — количество кадров, в котором они зафиксированы. Подобрав эти значения, можно сделать так, что Motion не будет замечать пролетающую птицу, но без проблем реагировать на человека. Фильтры для сглаживания шума подключаются при помощи despeckle. По умолчанию используется оптимальное значение EedDl. При появлении проблем следует поэкспериментировать, убирая буквы в сочетании EedDl и пробуя их в разных комбинациях.
- Параметры noise_level, noise_tune, night_compensate и lightswitch отвечают за уровень порога шума и компенсацию темных и светлых участков.
- Комбинация параметров pre_capture, post_capture и gap позволяет записать законченную сцену, где будет снят контролируемый объект до и после того, как было обнаружено движение. Значение gap по умолчанию установлено в оптимальные 60 (секунд), если движение не будет обнаружено, то создается новый видеофайл, а старый удаляется. Чтобы захваченный файл не был большим, его продолжительность можно ограничить параметром max_mpeg_time, указав в качестве значения время в секундах.
После обновления видеосервера под debian, было принято решение переделать систему видеонаблюдения.
Motion было решено оставить, но возникла необходимость в более человеческом интерфейсе для просмотра архивных записей. Очередные поиски в Интернет так и не дали никаких приемлемых результатов, в результате чего было принято решение о создании собственного продукта. После небольших колебаний, выбор пал на Rails. Никакой религии, просто захотелось получше изучить этот фреймворк и замечательный язык программирования. В качестве СУБД используется PostgreSQL. Результат работы под капотом...
Для начала чуть-чуть поподробнее про настройку motion.
В связи с тем, что хотелось, по-возможности, обойтись чистым HTML5, пришлось переустановить motion вручную, включив ему поддержку записи файлов в ogg. Благо авторы данной программы реализовали ее, за что им большое спасибо. Процесс сборки и установки описан хорошо на странице проекта, поэтому не буду его здесь расписывать, тем более, что под разные дистрибутивы он будет отличаться. Ссылка на домашнюю страницу www.lavrsen.dk/foswiki/bin/view/Motion/MotionGuideInstallation.
Заострю внимание только на настройке продукта.
Так как изначально motion был установлен из пакетов, то после переустановки не стал переносить папку с конфигурацией из /etc в
/usr/local/etc
. И еще один пункт, сам motion запускается при помощи runit, поэтому в конфиге он отключен режим демона. Расстановка сил следующая:
- Конфиги motion лежат в /etc/motion.
- Видео пишется на отдельный жесткий диск, смонтированный в директорию /video, в папки с именами камер.
- В базу откладываются записи, в которых хранится информация о времени события, полному пути к файлу события, типом файла (в моем случае видео).
Структура таблицы
CREATE TABLE records
id serial NOT NULL,
thread integer,
filename character varying(255),
frame integer,
file_type integer,
event_timestamp timestamp without time zone,
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL,
CONSTRAINT records_pkey PRIMARY KEY (id)
WITH (
OIDS=FALSE
);
ALTER TABLE records
OWNER TO motion;
Index: thread
DROP INDEX thread;
CREATE INDEX thread
ON records
USING btree
(thread);
4. Для живого просмотра (в режиме реального времени) с камер использутеся интерфейс motion.
Основные изменения в конфиге следующие:
/etc/motion.conf
ffmpeg_video_codec ogg
webcontrol_port 8080
webcontrol_localhost off (в том случае, если web-interface будет запускаться на другом сервере)
webcontrol_html_output on
webcontrol_authentication login:pass
sql_query insert into records(thread, filename, frame, file_type, event_timestamp, created_at, updated_at) values("%t", "%f", "%q", "%n", "%Y-%m-%d %T", NOW(), NOW())
И соответственно настройки для подключения к БД.
thread /etc/motion/thread1.conf
thread /etc/motion/thread2.conf
…
thread /etc/motion/threadN.conf,
где N зависит от количества наших камер.
Основные пункты в threadX.conf, где X - любое число
stream_port PortNumber - данный порт надо будет писать в поле «Порт потокового вещания» при настройке камер в web-interface. Это основные изменения при настройке motion. Как настроить сам motion в данной статье расписывать не буду. По настройке Rails хорошо расписано в статье habrahabr.ru/post/140910 . Также может возникнуть необходимость в установке NodeJS - github.com/joyent/node/wiki/Installing-Node.js-via-package-manager
Теперь перейдем непосредственно к настройке интерфейса:
1. Клонировать при помощи git сайт.
Bitbucket:
git clone [email protected]/webdev4u/motion_web.git
Github:
git clone github.com/webdev4u/motion_web.git
2. Переименовать
config/settings.local.yml
в
config/settings.yml
и вписать туда адрес сервера, на котором запущен motion.
3. Переименовать
config/database.yml.example
в
config/database.yml
и вписать туда настройки для вашей базы.
4. Измените данные в
db/seeds.rb
для пользователя
admin
.
5.
rake db:migrate
6.
rake db:seed
7. Для проверки можно будет запустить
rails s
. Сервер будет слушать на 3000 порту. Если все нормально, можно работать.
8. И напоследок, настроить задание для крона по чистке базы. По умолчанию хранятся записи за 21 день, но можно изменить этот параметр в файле
app/models/record.rb
12 строка, но лучше в
lib/tasks/crontask.rake
строку
Record.clean_old_records
заменить на
Record.clean_old_records Нужное_количество_дней.
После чего прогнать команду
whenever --update-crontab
из под пользователя, от имени которого будет работать сайт.
Скриншоты
Скриншот главной страницы:
Страница входа:
Живой просмотр:
Список камер:
Просмотр архива:
Добавление пользователя:
Добавление камеры:
Лирика
Добрый день. Мотивированный многочисленными постами на Хабре о самодельных роботах решил сделать и что-нибудь свое более менее стоящее и интересное.
Вообще роботами я увлекаюсь давно, но до нормального проекта руки не доходили, в основном только игрался. Немного подумав, придумал свой проект, поискал детали, нарисовал наброски, пофантазировал на тему будущих возможностей робота. Детали заказал не небезызвестном сайте, и пока детали преодолевают путь из поднебесной решил реализовать один из модулей будущего робота из того что есть под рукой. Вернее даже не реализовать сам модуль, а собрать прототип и написать софт, чтобы потом не отвлекаться на написание программы, да и тем более пока идут все детали есть море свободного времени, а желание что-либо сделать, не дает покоя.
Под рукой у меня оказалась платка Arduino Diecimila, несколько сервоприводов, веб-камера, джойстик и ультразвуковой дальномер. Соответственно сразу возникло желание сделать «компьютерное зрение» на основе веб-камеры, с возможностью как автономной работы, так и ручного управления (джойстиком).
Что меня сподвигло написать эту статью?
Порывшись в интернете, я в основном находил всякий мусор, невнятные вопросы на форумах, отрывки из статей, немного отдаленных от потребностей. В общем и целом я не нашел хорошей, полноценной статьи, которая бы от начала и до конца описывала создание двигающейся веб-камеры, с примерами кода, а уж тем более совмещенные с дальномером и джойстиком.
Тогда решено было ничего больше не искать, так как времени на обработку статей и собирание во едино всей информации уходить стало больше, чем если делать все с нуля самому, тем более, что большинство статей уже давно устарело.
Задача ведь тривиальная, посылать информацию с джойстика на Arduino, которая на определенный угол будет поворачивать 2 сервопривода с прикрепленной веб-камерой, и по необходимости считывать информацию с дальномера, отсылая ее в SerialPort.
Обдумав все еще раз, решил приступить к созданию данного прототипа самостоятельно. Поехали!
Основная часть
Сборка прототипа
Прототип был создан в течение 5 минут. Внешний вид прототипа не интересует вообще, основная его цель - отработка программной части до приезда деталей для робота.
А сделал я его из первой попавшейся баночки из под каких-то витаминов, двух сервоприводов, веб-камеры, скрепки, изоленты и клеевого пистолета. Получилось следующее:
Фото
Сборка завершена, сервоприводы и ультразвуковой дальномер подключены к Arduino, Arduino к ПК, приступаем к программированию Arduino.
Программируем Arduino
Тут все казалось очень просто, так как джойстик подключается к ПК, основная обработка видео тоже будет на ПК, то Arduino займется лишь приемом и обработкой информации с ПК и управлением сервоприводами. Поэтому нам надо лишь читать Serial Port, обрабатывать каким-то образом поступающую информацию и как-то на нее реагировать.
Забегая немного вперед сразу скажу, тут и произошла ошибка, к которой мне пришлось вернуться уже после написания программы на C#. Ошибка была вот в чем - я, наивный и полный энтузиазма, написал программку которая разбирает поступающую в Serial Port строку примерно следующего вида «90:90» на две части, соответственно первая часть это градусы по координате X, вторая часть Y. При помощи монитора порта все было оттестировано и работало прекрасно, но когда была написана программа для управления с джойстика, при усиленной атаке порта строками с изменяющимися значениями, Arduino просто не успевала считывать все последовательно, поэтому зачастую строки превращались в «0:909», ":9090" и тому подобное.
Соответственно сервоприводы сходили с ума и принимали все положения, кроме тех, что нужны нам.
Поэтому, не долго думая, я пришел к выводу что нам нужен символ начала строки и символ конца строки. Опять же, не долго думая, символом начала строки был выбран первый символ латинского алфавита - «a», концом строки последний - «z», а символы начала значений осей «x» и «y» соответственно. Итого входная строка принимала следующий вид: «ax90y90z».
Все бы хорошо, если бы не дальномер. Дальномер ультразвуковой, расстояние он определяет на ура, но есть несколько нюансов. Во-первых, если угол между дальномером и стеной острее 45 градусов (плюс-минус), то звук отражается от стены по касательной, и значение, не соответствует действительности. Во-вторых довольно большой угол испускания сигнала, около 30 градусов(по мануалу), а замеряется расстояние до ближайшего объекта, благо что сигнал от объектов к которым датчик находится под углом, отражается в другую сторону, и мы получаем более менее реальное расстояние по прямой, но помехи все же бывают, и довольно часто. Поэтому я дописал еще одну функцию, которая берет n замеров расстояния, складывает их и делит на кол-во, выставил n=10, так помехи стали более сглажены и менее заметны.
Код на Arduino был тут же переписан и принял следующий вид:
Код Arduino
#include Проблема с неправильным разбором координат исчезла на совсем, 100 из 100 испытаний пройдены успешно. По началу хотел писать все на C++ под Qt, но в последствии все же пришлось писать на C#, ну да ладно. Что хотелось получить: Для распознавания лиц и вывода изображения с веб-камеры, без всяких вопросов, была выбрана библиотека OpenCV, а вернее ее оболочка для C# - Emgu CV. Для считывания положения джойстика по началу использовалась библиотека Microsoft.DirectX.DirectInput, которая мне жутко не понравилась, и я применил библиотеку SharpDX, притом довольно успешно. Что требовалось от программы: Сформулировав задачи, приступаем к программированию. Библиотечка SharpDX позволяет нам находить подключенный джойстик и получать с него значения осей (от 0 до 65535), нажатие и отпускание клавиш джойстика. Сервоприводы могут поворачиваться от 0 до 180 градусов, соответственно нужно преобразовывать значения осей джойстика от 0 до 180. Я просто поделил возвращаемое значение на 363, и получил на выходе значения от 0 до 180. Далее написал функцию которая формирует строку положения сервоприводов и отправляет ее в порт. Вывод изображения и распознавание лиц написаны с использованием OpenCV и ничего сложного не представляют (для нас). Повторив тригонометрию и вектора, написал процедуру, которая вычисляет координаты точки относительно нашего дальномера с камерой по углу поворота сервопривода и расстоянию до объекта, и рисует полученные результаты в PictureBox, по кнопке запускаю процедуру в потоке, все работает, но все же из за рельефа комнаты получаются довольно большие помехи, но примерное очертание совпадает с действительностью. Пытался сглаживать данные с датчика, выбирая лишь пиковые значения и рисуя между ними отрезки, в принципе получилось не плохо, но решил отказаться от этого, так как часто пиковыми значениями становятся именно помехи. Код (на всякий случай с подробными комментариями, по возможности): Класс формы
Capture myCapture;
private bool captureInProgress = false;
string _distance = "0";
string coords;
int X_joy = 90;
int Y_joy = 90;
SerialPort _serialPort = new SerialPort();
Image Класс DetectFace
Class DetectFace
{
public static void Detect(Image В итоге получаем все, что хотели. Компьютер распознает лица и автоматически следит за ними. ручное управление джойстиком работает на ура. Радар, хоть и не совсем точно, но работает. Основные функции модуля зрения робота отработаны и остается лишь дорабатывать и усовершенствовать их. Вот, что получилось по завершении.
Оказалось все довольно просто. Цель достигнута, прототип готов. Есть над чем работать и заняться в свободное время, ожидая посылку с компонентами для робота. Следующим шагом будет построение колесной платформы для робота, настройка удаленного управления (WiFi, 3G)., навешивание датчиков (температура, давление и прочее), синтез речи. В хотелках так же имеются планы по поводу механической руки. Думаю, если будет интерес к данной статье и ее продолжению, то оно обязательно последует! Исправления и критика приветствуются! Спасибо за внимание! Вообще роботами я увлекаюсь давно, но до нормального проекта руки не доходили, в основном только игрался. Немного подумав, придумал свой проект, поискал детали, нарисовал наброски, пофантазировал на тему будущих возможностей робота. Детали заказал не небезызвестном сайте, и пока детали преодолевают путь из поднебесной решил реализовать один из модулей будущего робота из того что есть под рукой. Вернее даже не реализовать сам модуль, а собрать прототип и написать софт, чтобы потом не отвлекаться на написание программы, да и тем более пока идут все детали есть море свободного времени, а желание что-либо сделать, не дает покоя. Под рукой у меня оказалась платка Arduino Diecimila, несколько сервоприводов, веб-камера, джойстик и ультразвуковой дальномер. Соответственно сразу возникло желание сделать «компьютерное зрение» на основе веб-камеры, с возможностью как автономной работы, так и ручного управления (джойстиком). Задача ведь тривиальная, посылать информацию с джойстика на Arduino, которая на определенный угол будет поворачивать 2 сервопривода с прикрепленной веб-камерой, и по необходимости считывать информацию с дальномера, отсылая ее в SerialPort. Фото
Сборка завершена, сервоприводы и ультразвуковой дальномер подключены к Arduino, Arduino к ПК, приступаем к программированию Arduino. Забегая немного вперед сразу скажу, тут и произошла ошибка, к которой мне пришлось вернуться уже после написания программы на C#. Ошибка была вот в чем - я, наивный и полный энтузиазма, написал программку которая разбирает поступающую в Serial Port строку примерно следующего вида «90:90» на две части, соответственно первая часть это градусы по координате X, вторая часть Y. При помощи монитора порта все было оттестировано и работало прекрасно, но когда была написана программа для управления с джойстика, при усиленной атаке порта строками с изменяющимися значениями, Arduino просто не успевала считывать все последовательно, поэтому зачастую строки превращались в «0:909», ":9090" и тому подобное. Поэтому, не долго думая, я пришел к выводу что нам нужен символ начала строки и символ конца строки. Опять же, не долго думая, символом начала строки был выбран первый символ латинского алфавита - «a», концом строки последний - «z», а символы начала значений осей «x» и «y» соответственно. Итого входная строка принимала следующий вид: «ax90y90z». Все бы хорошо, если бы не дальномер. Дальномер ультразвуковой, расстояние он определяет на ура, но есть несколько нюансов. Во-первых, если угол между дальномером и стеной острее 45 градусов (плюс-минус), то звук отражается от стены по касательной, и значение, не соответствует действительности. Во-вторых довольно большой угол испускания сигнала, около 30 градусов(по мануалу), а замеряется расстояние до ближайшего объекта, благо что сигнал от объектов к которым датчик находится под углом, отражается в другую сторону, и мы получаем более менее реальное расстояние по прямой, но помехи все же бывают, и довольно часто. Поэтому я дописал еще одну функцию, которая берет n замеров расстояния, складывает их и делит на кол-во, выставил n=10, так помехи стали более сглажены и менее заметны. Код на Arduino был тут же переписан и принял следующий вид: Код Arduino
#include Проблема с неправильным разбором координат исчезла на совсем, 100 из 100 испытаний пройдены успешно. Что хотелось получить: Для распознавания лиц и вывода изображения с веб-камеры, без всяких вопросов, была выбрана библиотека OpenCV, а вернее ее оболочка для C# - Emgu CV. Для считывания положения джойстика по началу использовалась библиотека Microsoft.DirectX.DirectInput, которая мне жутко не понравилась, и я применил библиотеку SharpDX, притом довольно успешно. Что требовалось от программы: Сформулировав задачи, приступаем к программированию. Библиотечка SharpDX позволяет нам находить подключенный джойстик и получать с него значения осей (от 0 до 65535), нажатие и отпускание клавиш джойстика. Сервоприводы могут поворачиваться от 0 до 180 градусов, соответственно нужно преобразовывать значения осей джойстика от 0 до 180. Я просто поделил возвращаемое значение на 363, и получил на выходе значения от 0 до 180. Далее написал функцию которая формирует строку положения сервоприводов и отправляет ее в порт. Вывод изображения и распознавание лиц написаны с использованием OpenCV и ничего сложного не представляют (для нас). Повторив тригонометрию и вектора, написал процедуру, которая вычисляет координаты точки относительно нашего дальномера с камерой по углу поворота сервопривода и расстоянию до объекта, и рисует полученные результаты в PictureBox, по кнопке запускаю процедуру в потоке, все работает, но все же из за рельефа комнаты получаются довольно большие помехи, но примерное очертание совпадает с действительностью. Пытался сглаживать данные с датчика, выбирая лишь пиковые значения и рисуя между ними отрезки, в принципе получилось не плохо, но решил отказаться от этого, так как часто пиковыми значениями становятся именно помехи. Код (на всякий случай с подробными комментариями, по возможности): Класс формы
Capture myCapture;
private bool captureInProgress = false;
string _distance = "0";
string coords;
int X_joy = 90;
int Y_joy = 90;
SerialPort _serialPort = new SerialPort();
Image Класс DetectFace
class DetectFace
{
public static void Detect(Image В итоге получаем все, что хотели. Компьютер распознает лица и автоматически следит за ними. ручное управление джойстиком работает на ура. Радар, хоть и не совсем точно, но работает. Основные функции модуля зрения робота отработаны и остается лишь дорабатывать и усовершенствовать их. Думаю, если будет интерес к данной статье и ее продолжению, то оно обязательно последует! Исправления и критика приветствуются! Спасибо за внимание! Теги:
Вообще роботами я увлекаюсь давно, но до нормального проекта руки не доходили, в основном только игрался. Немного подумав, придумал свой проект, поискал детали, нарисовал наброски, пофантазировал на тему будущих возможностей робота. Детали заказал не небезызвестном сайте, и пока детали преодолевают путь из поднебесной решил реализовать один из модулей будущего робота из того что есть под рукой. Вернее даже не реализовать сам модуль, а собрать прототип и написать софт, чтобы потом не отвлекаться на написание программы, да и тем более пока идут все детали есть море свободного времени, а желание что-либо сделать, не дает покоя. Под рукой у меня оказалась платка Arduino Diecimila, несколько сервоприводов, веб-камера, джойстик и ультразвуковой дальномер. Соответственно сразу возникло желание сделать «компьютерное зрение» на основе веб-камеры, с возможностью как автономной работы, так и ручного управления (джойстиком). Задача ведь тривиальная, посылать информацию с джойстика на Arduino, которая на определенный угол будет поворачивать 2 сервопривода с прикрепленной веб-камерой, и по необходимости считывать информацию с дальномера, отсылая ее в SerialPort. Фото
Сборка завершена, сервоприводы и ультразвуковой дальномер подключены к Arduino, Arduino к ПК, приступаем к программированию Arduino. Забегая немного вперед сразу скажу, тут и произошла ошибка, к которой мне пришлось вернуться уже после написания программы на C#. Ошибка была вот в чем — я, наивный и полный энтузиазма, написал программку которая разбирает поступающую в Serial Port строку примерно следующего вида «90:90» на две части, соответственно первая часть это градусы по координате X, вторая часть Y. При помощи монитора порта все было оттестировано и работало прекрасно, но когда была написана программа для управления с джойстика, при усиленной атаке порта строками с изменяющимися значениями, Arduino просто не успевала считывать все последовательно, поэтому зачастую строки превращались в «0:909», ":9090" и тому подобное. Поэтому, не долго думая, я пришел к выводу что нам нужен символ начала строки и символ конца строки. Опять же, не долго думая, символом начала строки был выбран первый символ латинского алфавита — «a», концом строки последний — «z», а символы начала значений осей «x» и «y» соответственно. Итого входная строка принимала следующий вид: «ax90y90z». Все бы хорошо, если бы не дальномер. Дальномер ультразвуковой, расстояние он определяет на ура, но есть несколько нюансов. Во-первых, если угол между дальномером и стеной острее 45 градусов (плюс-минус), то звук отражается от стены по касательной, и значение, не соответствует действительности. Во-вторых довольно большой угол испускания сигнала, около 30 градусов(по мануалу), а замеряется расстояние до ближайшего объекта, благо что сигнал от объектов к которым датчик находится под углом, отражается в другую сторону, и мы получаем более менее реальное расстояние по прямой, но помехи все же бывают, и довольно часто. Поэтому я дописал еще одну функцию, которая берет n замеров расстояния, складывает их и делит на кол-во, выставил n=10, так помехи стали более сглажены и менее заметны. Код на Arduino был тут же переписан и принял следующий вид: Код Arduino
#include Проблема с неправильным разбором координат исчезла на совсем, 100 из 100 испытаний пройдены успешно. Что хотелось получить: Для распознавания лиц и вывода изображения с веб-камеры, без всяких вопросов, была выбрана библиотека OpenCV, а вернее ее оболочка для C# — Emgu CV. Для считывания положения джойстика по началу использовалась библиотека Microsoft.DirectX.DirectInput, которая мне жутко не понравилась, и я применил библиотеку SharpDX, притом довольно успешно. Что требовалось от программы: Сформулировав задачи, приступаем к программированию. Библиотечка SharpDX позволяет нам находить подключенный джойстик и получать с него значения осей (от 0 до 65535), нажатие и отпускание клавиш джойстика. Сервоприводы могут поворачиваться от 0 до 180 градусов, соответственно нужно преобразовывать значения осей джойстика от 0 до 180. Я просто поделил возвращаемое значение на 363, и получил на выходе значения от 0 до 180. Далее написал функцию которая формирует строку положения сервоприводов и отправляет ее в порт. Вывод изображения и распознавание лиц написаны с использованием OpenCV и ничего сложного не представляют (для нас). Повторив тригонометрию и вектора, написал процедуру, которая вычисляет координаты точки относительно нашего дальномера с камерой по углу поворота сервопривода и расстоянию до объекта, и рисует полученные результаты в PictureBox, по кнопке запускаю процедуру в потоке, все работает, но все же из за рельефа комнаты получаются довольно большие помехи, но примерное очертание совпадает с действительностью. Пытался сглаживать данные с датчика, выбирая лишь пиковые значения и рисуя между ними отрезки, в принципе получилось не плохо, но решил отказаться от этого, так как часто пиковыми значениями становятся именно помехи. Код (на всякий случай с подробными комментариями, по возможности): Класс формы
Capture myCapture;
private bool captureInProgress = false;
string _distance = "0";
string coords;
int X_joy = 90;
int Y_joy = 90;
SerialPort _serialPort = new SerialPort();
Image Класс DetectFace
class DetectFace
{
public static void Detect(Image В итоге получаем все, что хотели. Компьютер распознает лица и автоматически следит за ними. ручное управление джойстиком работает на ура. Радар, хоть и не совсем точно, но работает. Основные функции модуля зрения робота отработаны и остается лишь дорабатывать и усовершенствовать их. Думаю, если будет интерес к данной статье и ее продолжению, то оно обязательно последует! Исправления и критика приветствуются! Спасибо за внимание!Основная управляющая программа (C#)
1. Распознавание лиц людей.
2. Слежение за лицом человека.
3. Ручное управление с помощью джойстика.
4. Определение расстояния до объекта.
1. Захватывать изображение с веб-камеры и выводить его на экран.
2. Распознавать лица на изображении, обводить их и получать координаты лица на изображении.
3. Формировать строку вида «ax90y90z» и отправлять ее в Serial Port для управления сервоприводами.
4. Считывать значения положения джойстика.
5. Считывать показания с дальномера.Видео
Заключение
Итоги
Планы на будущее
Лирика
Добрый день. Мотивированный многочисленными постами на Хабре о самодельных роботах решил сделать и что-нибудь свое более менее стоящее и интересное.Что меня сподвигло написать эту статью?
Порывшись в интернете, я в основном находил всякий мусор, невнятные вопросы на форумах, отрывки из статей, немного отдаленных от потребностей. В общем и целом я не нашел хорошей, полноценной статьи, которая бы от начала и до конца описывала создание двигающейся веб-камеры, с примерами кода, а уж тем более совмещенные с дальномером и джойстиком.
Тогда решено было ничего больше не искать, так как времени на обработку статей и собирание во едино всей информации уходить стало больше, чем если делать все с нуля самому, тем более, что большинство статей уже давно устарело.
Обдумав все еще раз, решил приступить к созданию данного прототипа самостоятельно. Поехали!Основная часть
Сборка прототипа
Прототип был создан в течение 5 минут. Внешний вид прототипа не интересует вообще, основная его цель - отработка программной части до приезда деталей для робота.
А сделал я его из первой попавшейся баночки из под каких-то витаминов, двух сервоприводов, веб-камеры, скрепки, изоленты и клеевого пистолета. Получилось следующее:Программируем Arduino
Тут все казалось очень просто, так как джойстик подключается к ПК, основная обработка видео тоже будет на ПК, то Arduino займется лишь приемом и обработкой информации с ПК и управлением сервоприводами. Поэтому нам надо лишь читать Serial Port, обрабатывать каким-то образом поступающую информацию и как-то на нее реагировать.
Соответственно сервоприводы сходили с ума и принимали все положения, кроме тех, что нужны нам.Основная управляющая программа (C#)
По началу хотел писать все на C++ под Qt, но в последствии все же пришлось писать на C#, ну да ладно.
1. Распознавание лиц людей.
2. Слежение за лицом человека.
3. Ручное управление с помощью джойстика.
4. Определение расстояния до объекта.
1. Захватывать изображение с веб-камеры и выводить его на экран.
2. Распознавать лица на изображении, обводить их и получать координаты лица на изображении.
3. Формировать строку вида «ax90y90z» и отправлять ее в Serial Port для управления сервоприводами.
4. Считывать значения положения джойстика.
5. Считывать показания с дальномера.Видео
Вот, что получилось по завершении.Заключение
Итоги
Оказалось все довольно просто. Цель достигнута, прототип готов. Есть над чем работать и заняться в свободное время, ожидая посылку с компонентами для робота.Планы на будущее
Следующим шагом будет построение колесной платформы для робота, настройка удаленного управления (WiFi, 3G)., навешивание датчиков (температура, давление и прочее), синтез речи. В хотелках так же имеются планы по поводу механической руки.
Добавить метки
Лирика
Добрый день. Мотивированный многочисленными постами на Хабре о самодельных роботах решил сделать и что-нибудь свое более менее стоящее и интересное.Что меня сподвигло написать эту статью?
Порывшись в интернете, я в основном находил всякий мусор, невнятные вопросы на форумах, отрывки из статей, немного отдаленных от потребностей. В общем и целом я не нашел хорошей, полноценной статьи, которая бы от начала и до конца описывала создание двигающейся веб-камеры, с примерами кода, а уж тем более совмещенные с дальномером и джойстиком.
Тогда решено было ничего больше не искать, так как времени на обработку статей и собирание во едино всей информации уходить стало больше, чем если делать все с нуля самому, тем более, что большинство статей уже давно устарело.
Обдумав все еще раз, решил приступить к созданию данного прототипа самостоятельно. Поехали!Основная часть
Сборка прототипа
Прототип был создан в течение 5 минут. Внешний вид прототипа не интересует вообще, основная его цель — отработка программной части до приезда деталей для робота.
А сделал я его из первой попавшейся баночки из под каких-то витаминов, двух сервоприводов, веб-камеры, скрепки, изоленты и клеевого пистолета. Получилось следующее:Программируем Arduino
Тут все казалось очень просто, так как джойстик подключается к ПК, основная обработка видео тоже будет на ПК, то Arduino займется лишь приемом и обработкой информации с ПК и управлением сервоприводами. Поэтому нам надо лишь читать Serial Port, обрабатывать каким-то образом поступающую информацию и как-то на нее реагировать.
Соответственно сервоприводы сходили с ума и принимали все положения, кроме тех, что нужны нам.Основная управляющая программа (C#)
По началу хотел писать все на C++ под Qt, но в последствии все же пришлось писать на C#, ну да ладно.
1. Распознавание лиц людей.
2. Слежение за лицом человека.
3. Ручное управление с помощью джойстика.
4. Определение расстояния до объекта.
1. Захватывать изображение с веб-камеры и выводить его на экран.
2. Распознавать лица на изображении, обводить их и получать координаты лица на изображении.
3. Формировать строку вида «ax90y90z» и отправлять ее в Serial Port для управления сервоприводами.
4. Считывать значения положения джойстика.
5. Считывать показания с дальномера.Видео
Вот, что получилось по завершении.Заключение
Итоги
Оказалось все довольно просто. Цель достигнута, прототип готов. Есть над чем работать и заняться в свободное время, ожидая посылку с компонентами для робота.Планы на будущее
Следующим шагом будет построение колесной платформы для робота, настройка удаленного управления (WiFi, 3G)., навешивание датчиков (температура, давление и прочее), синтез речи. В хотелках так же имеются планы по поводу механической руки.