Последние статьи
- Твердотельный датчик направления и скорости ветра. Эксперимент
- iPhone на стене в качестве панели управления домом
- MegaD-16M-XT - подсветка выключателей и не только
- Переделка выключателей в кнопки и мини-обзор текущего рынка
- RadSens - модульный счетчик Гейгера с интерфейсом I2C
- "U" - значит универсальный. Обзор модуля MegaD-16U-XT
- SCD4x - современная альтернатива для измерения концентрации CO2
- HTU31D - новый датчик температуры и влажности с нагревательным элементом
- Измерение коэффициента пульсации ламп с помощью MegaD-2561
- Использование солнечных панелей в качестве датчика освещенности
- Согласование датчиков с выходом типа TTL со стандартными входами контроллера
- DPS368 - датчик атмосферного давления индустриального класса повышенной точности
- DS18B20 Waterpoof - импортзамещение
- TMP117 - высокоточный датчик температуры с интерфейсом I2C
- MegaD-16R-XT - расширитель на 16 релейных выходов
- MegaD-2561-RTC V3 - больше портов, зуммер и ИОН
Анализ изображений с помощью нейронной сети
21/10/2010 15:10:03
Возможно, данная статья устарела.
Все новые статьи
В предыдущей статье "Применение нейронных сетей в Умном Доме" я коротко описал ситуации, в которых можно применять нейросети, а также их возможности. Теперь я попытаюсь воспользоваться нейросетью для анализа фотоизображения с камеры наблюдения.
У меня установлена камера наблюдения, которая обращена на улицу. В кадр попадает площадка для автомобиля перед входом. Я хотел бы научить нейросеть распознавать - стоит ли мой автомобиль на площадке, а также по возможности отличать мой автомобиль от других. Эту информацию можно использовать различным образом. Например, включать подогрев чайника в обед, сообщать домочадцам о моем приезде, включать освещение крыльца, напоминать мне, если в лютый зимний мороз я, вдруг, забыл загнать автомобиль в гараж и т.д. В случае обнаружения на площадке чужого автомобиля в режиме охраны, сообщать об этом факте по SMS или изменить параметр на входе другой нейросети, отвечающей за охрану дома. Как интерпретировать и использовать полученные данные можно рассуждать бесконечно. А в данный момент необходимо определить факт стоянки автомобиля, не человека и не велосипедиста, а именно автомобиля, причем моего.
Для создания и работы с собственной нейронной сетью я воспользовался библиотекой FANN. В Debian Linux в стабильном репозитории доступна версия 1.2.0 этой библиотеки
apt-get install libfann1 apt-get install libfann1-dev
Скачать и распаковать http://pecl.php.net/package/fann
phpize5 (если его нет в системе, необходимо установить php5-dev)
./configure
make
При компиляции PHP-FANN с установленной PHP5 возникает следующая ошибка:
fann.c:393: error: ‘zif_fannOO___set’ undeclared (first use in this function)
Необходимо отредактировать файл
php_fann.h
и закомментировать строчку 28
#define PHP_FANN_OO 1
make
make install
Далее добавляем в php.ini
extension=fann.so
и перезапускаем Apache (если мы используем PHP из Web-сервера а не в режиме CLI)
/etc/init.d/apache2 restart
Прежде чем использовать нейросеть ее нужно обучить на некоторых данных. Поскольку у меня ведется архив с камеры наблюдения, я подготовил ряд фотографий, на которых мой автомобиль стоит на площадке и ряд других фотографий, где автомобиля нет. Я постарался выбрать фотографии в разную погоду, а также при искусственном освещении. Для начала я взял по 6 фотографий с автомобилем и без и положил их в две разные папки: 1 и 0.
У нас есть обучающий материал и можно приступить к обучению сети. Обычно задачу обучения сети, особенно когда речь заходит о большом количестве данных, выносят в отдельный процесс. Сделал так и я.
Для экономии времени и ресурсов, я анализирую не все изображение, а только часть кадра, в который вписана площадка (камера зафиксирована и не поворачивается). В графическом редакторе я определил, что эта часть кадра прямоугольник с координатами в пикселах (125х150; 350х150; 125х230; 350х230). Так как сеть работает с данными, необходимо предоставить ей массив данных, характеризующих изображение. Для этого можно считать код цвета каждого пиксела, например, функцией imagecolorat().
Нейронной сети удобнее работать с нормализованными данными, которые приведены к диапазону [-1;1] или [0;1]. В моем примере мы имеем диапазон значений от 0 (абсолютно черный цвет) до 16777215 (абсолютно белый цвет), поэтому каждое значение я делю на максимальное и получаю число в диапазоне от 0 до 1.
Несколько слов о параметрах создаваемой сети. Кроп с изображением площадки для автомобиля представляет собой массив из 18000 пикселей. (225х80). Поэтому мы должны создать нейронную сеть с 18000 нейронами на входе. В среднем, так называемом, скрытом слое находится 100 нейронов. Человек, который очень хорошо представляет математическую модель нейронной сети, принципы ее работы в различных ситуациях может более-менее адекватно прикинуть оптимальное количество нейронов на этом уровне. Для остальных действует простое правило - подбирается эмпирическим путем, то есть опытным. Мы можем попробовать разное количество нейронов и посмотреть на результаты обучения: скорость обучения, количество итераций, количество ошибок. На выходе сети в моем случае 1 нейрон. Это означает, что ответ сети будет один и находится в области значений между 0 и 1. Ноль или близкие к нулю значения будут говорить, что моего автомобиля нет на площадке, тогда как единица будет сообщать, что автомобиль стоит на площадке. Относительно остальных параметров нейронной сети можно посмотреть в документации к библиотеке FANN.
Код программы:
<? // Считываем данные с обучающих фотографий в массив. $j = 0; $my_example = array(); for ( $i = 0; $i < 2; $i++ ) { $d = dir("teach/$i"); while($entry = $d->read()) { if ( preg_match("/jpg/", $entry) ) { $im = imagecreatefromjpeg("teach/$i/$entry"); $cur_array = array(); $cnt = 0; for($y=150; $y<230; $y++) { for($x=125; $x < 350; $x++) { $rgb = imagecolorat($im, $x, $y) / 16777215; $cur_array[$cnt] = $rgb; $cnt++; } } imagedestroy($im); $my_example[$j] = array($cur_array, array($i)); $j++; } } } // Создаем и обучаем сеть $ann = fann_create(array(18000, 100, 1), 1.0, 0.7); if ( fann_train($ann, $my_example, 1000, 0.001, 1000) == FALSE) exit('Could not train $ann.'); // Сохраняем обученную сеть в файл для дальнейшего использования. fann_save($ann, "my.ann");
Обучение на компьютере с процессором Celeron 1,6ГГц заняло примерно 30-40 секунд. В результате я получил файл объемом 60Мб.
Теперь мы можем использовать обученную сеть:
<? $ann = fann_create("my.ann"); $im = imagecreatefromjpeg("snap/camera.jpg"); $cur_array = array(); $cnt = 0; for($y=150; $y<230; $y++) { for($x=125; $x < 350; $x++) { $rgb = imagecolorat($im, $x, $y) / 16777215; $cur_array[$cnt] = $rgb; $cnt++; } } imagedestroy($im); if ( ($output = fann_run($ann, $cur_array)) == FALSE ) exit("Could not run ANN."); else print_r($output); ?>
На площадке нет автомобиля.
После запуска скрипта, программа выдала значение: 0.0391430146992.
Этот ответ можно смело квалифицировать как ответ "Нет".
Далее, ставим автомобиль на площадку и снова запускаем программу. Ответ: 0.988427102566
Очевидно, что программа сообщила "Да".
Работа такого скрипта занимает порядка 3-4 секунд, так как программе требуется загрузить 60Мб файл с описанием сети, но если запустить этот скрипт в режиме демона, то обработка новых изображений происходит мгновенно.
Я умышленно не стал на этом этапе показывать сети зимние фотографии площадки, так как хочу понаблюдать за ответами нейросети в ситуации, когда условия изменятся. Также я настроил программный механизм, который ведет своеобразный журнал ответов. В случае, если сеть отвечает "Да", программа сохраняет картинку в журнал. В свободное время я просматриваю журнал и когда вижу, что сеть дала неправильный ответ, нажимаю кнопку "Ошибка" и этот файл добавляется в нужную папку для обучения. Если в папке с обучающим материалом меняется содержимое, происходит новый процесс обучения. На текущий момент сеть, обученная всего на 12 фотографиях, ни разу не ошиблась, но и сложных ситуаций пока не возникало.
В рамках этой статьи я буду добавлять информацию о поведении нейронной сети, сообщать о своем опыте, а также попытаюсь сделать какие-то практические выводы по поводу целесообразности такого подхода в системах домашней автоматизации. Буду рад любым конструктивным замечаниям и предложениям.
Автор: Andrey_B
Любое использование материалов сайта возможно только с разрешения автора и с обязательным указанием источника.
Добавить комментарий:
Сортировка комментариев: Последние сверху | Первые сверху
2014-05-26 20:58:09 | den
помогите написать программу по нейронным сетям на visual prolog
2013-10-10 21:05:34 | IvanSCM
Отличная статья, спасибо!
2012-01-04 19:23:27 | pk
при использовании такого примитивного алгоритма сеть надлежащим образом работать не будет.
2010-12-13 08:00:16 | stpavel
Странно. У меня поднялось все без проблем, сперва был скомпилен fann-1.2.0 , затем через pear fann-php. Может быть у Вас не хватает каких то библиотек , требуемых для fann ?
2010-12-11 12:47:58 | Naural tester
stpavel, я вам завидую, как вам так легко получилось поднять FANN на PHP. Я несколько дней мучаюсь с этой проблемой. Пробовал через PEAR, качал сорсы пхп в /ext добавлял fann, но у меня так ничего и не вышло, было бы отлично если бы кто-нибудь об этом рассказал, ведь в интернете нет об этом ни какой информации даже на английском языке.
2010-10-28 15:45:24 | Andrey_B
stpavel, к вам просьба. Если ваш опыт окажется позитивным обязательно расскажите какую задачу вы решали, на каком оборудовании и каким способом.
2010-10-28 14:01:51 | stpavel
Добавил массив, все работает , спасибо ! :) Буду обучать камеру на своих домашних
2010-10-28 12:07:20 | Andrey_B
stpavel, в описанном вами случае предложенная в статье простейшая программа не подойдет. В моем примере в качестве ответа фигурирует только 1 нейрон с возможными значениями 0 или 1, только один элемент в массиве правильных ответов. В вашем случае, массив правильных ответов должен содержать 3 элемента.
===
Ну, например,
1 0 0 - это значит "1"
0 1 0 - это значит "2"
0 0 1 - это значит "3"
===
в качестве ответа должно быть нормализованное значение, приведенное к диапазону [-1;1] или [0;1].
Обучив таким образом сеть, мы будем получать ответы, также представленный массивом, в котором возможны значения, например:
0,023 0,918 0,016 - Сеть думает, что это цифра "2".
Мы можем получить в качестве ответа и такое
0,992 0,942 0,217 - Это означает, что сеть не знает, и "предполагает" что это либо 1, либо 2. Это в свою очередь значит, что либо обучающий материал не совсем адекватен реальной жизни, либо представленная картинка является для сети "новой" и обучающий материал не содержит точного ответа для такой ситуации.
2010-10-28 10:27:43 | stpavel
идентификатор того что массив изображения принадлежит к той или иной группе изображений , вот что я имел ввиду.
2010-10-28 08:47:25 | stpavel
Решил немного усложнить задачу, попробовать научить скрипт различать три разных объекта. Нарисовал цифры 1, 2 и 3 с разрешением 50x50 пикселей. Получается, у нас 2500 нейронов на входе и 3 на выходе, промежуточный слой оставил 100.
Создаю и обучаю сеть:
$ann = fann_create(array(2500, 100, 3), 1.0, 0.7);
fann_train($ann, $my_example, 1000, 0.001, 10)
в результате получаю примерно следующее :
Epochs 1. Current error: 0.9044302225
Epochs 10. Current error: 0.8346135015
Epochs 20. Current error: 0.6666666667
Epochs 30. Current error: 0.6666666667
Epochs 40. Current error: 0.6666666667
т.е. погрешность как бы зацикливается и больше не стремится к 0.
Меня немного смущает массив $my_example, передаваемый fann_train.
Массив $my_example содержит два элемента, первый элемент с индексом 0 - массив разложенного изображения ( в моем случае 2500 элементов), второй элемент с индексом 1 также массив, имеющий всего одно значение ( в Вашем примере эти значения 0 или 1 в зависимости от папки , с которых берутся изображения) в моем случае 0, 1, 2. Не знаю, может быть эти значения не могут быть больше единицы.. Хотя с другой стороны, это просто идентификатор того что массив изображения принадлежит тому или иному изображению...
2010-10-28 00:00:00 | Andrey_B
stpavel, к вам просьба. Если ваш опыт окажется позитивным обязательно расскажите о том, какую задачу, на каком оборудовании и каким способом вы это сделали.
2010-10-24 23:17:50 | Andrey_B
stpavel, большое спасибо за ссылки. И хотя моя основная задача была попробовать нейронные сети в деле, предложенное вами направление распознавания объектов само по себе очень интересное. Обязательно попробую.
2010-10-24 18:23:57 | stpavel
Очень интересная статья, спасибо !
Андрей, а Вы не пробовали библиотеку opencv ? Судя по описанию и возможностям очень мощная библиотека для распознавания объектов. Примеры можно посмотреть здесь /www.computer-vision-software.com/blog/category/opencv/. Существует так же порт openvc под php для распознавания лиц - /www.xarg.org/project/php-facedetect/ . Еще один интересный проект - распознавание автомобильных номеров /javaanpr.sourceforge.net/, вроде бы даже как и рабочий, жаль нет возможности проверить его в боевых условиях.
2010-10-23 13:01:05 | THK
Впечатляет!
Жаль, что у меня камера видит только часть машины. Камера "врезана" в калитку и развернуть ее нет возможности. Зато можно попробовать натаскать сеть на лица. Зимой буду пробовать.
PS Еще раз спасибо за статью и за ответы.
2010-10-23 12:42:59 | Andrey_B
Машину паркую, конечно, по-разному. Смещение, думаю, больше метра. В этом случае сеть дает правильный ответ. Сегодня на площадке стояла другая машина, но сеть ее не признала как мою. Вместо 0.03 (когда машин совсем нет), сеть сказала 0.09. Что-то, говорит, стоит, но не твоя машина. ;)
2010-10-23 11:36:19 | THK
У меня на воротах такая-же камера... :(
И еще вопросик. Вы машину паркуете всегда одинаково или возможно ее "смещение" в кадре? К примеру +/- 0,5 метра.
И еще. Что скажет сеть, если "увидит" машину соседа на Вашем месте?
2010-10-22 23:51:58 | Andrey_B
ТНК, спасибо.
Задачу распознать номер я не ставлю. И вот почему. Фокусное расстояние моей камеры 3,6 мм. Она установлена в 10 метрах от машины и имеет ощутимую дисторсию. Площадь, которую занимает машина в кадре в пикселях составляет примерно 80 на 70. А номер машины занимает всего 14 на 5 пикселей. Совершенно очевидно, что нет возможности даже понять - написано ли что-нибудь вообще на номере. К тому же резкость камеры за 900 руб оставляет желать лучшего. Думаю, номер вполне реально распознать, но для этого нужно использовать камеру высокого разрешения, с более длинным фокусом. В будущем я планирую заменить камеру на более современную, а эту переориентирую за наблюдением сада.
Что касается количества нейронов на выходе, то для этого не обязательно 2000 нейронов. Все зависит от топологии сети и способа ее использования. Например, простой вариант - 3 цифры. Теоретически, мы должны порезать изображение на 3 кадра (как это сделать - отдельная история, но задача вполне решаемая) с цифрами в каждом кадре и подавать сети каждый кадр в отдельности. На выходе у такой сети будет 10 нейронов. Если, к примеру, третий нейрон дал 1, тогда как остальные 0 - значит на входе была цифра 3. Это при условии, что и обучали сеть мы аналогичным образом. Если несколько нейронов дали 1, значит сеть не смогла достоверно распознать цифру и нужно будет на более высоком уровне интерпретировать этот результат, отталкиваясь от конкретных значений. И человек не всегда может отличить 5 от 6.
Могу поделиться первыми наблюдениями. При очень низком освещении, фото которых не было в обучающем материале, сеть корректно решает задачу, хотя средняя яркость пикселей (а именно яркость подается на вход) значительно ниже. Возможно, сеть реагирует не на наличие темного пятна на фото, а на перепад яркости. Не зря утверждается, что сеть может выявить скрытые зависимости, которые не всегда очевидны даже человеку.
2010-10-22 22:46:06 | THK
Респект! Отличная статья!
А Вы не думали над задачей выделения номера машины из ее фото?
Насколько я понимаю, для этого придется на выходе получить не один нейрон, а скажем 2000 или сколько пикселей занимает номер на фото... Я прав?
Если да, то какой алгоритм обучения должен быть у этой сети?
PS Если вдруг я забегаю вперед (к теме следующей статьи) - сильно не пинайте... ;)