Опрос


Что для Вас Умный Дом?


Результаты

Фейс контроль, распознавание лиц в системе видеонаблюдения

11/10/2011 18:04:10

"Неча на зеркало пенять, коли рожа крива" (Народная поговорка)

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

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

Итак, оценив изображение с дешевой широкоугольной камеры типа "пинхол", я понял, что задачу распознавания лиц необходимо решать в два этапа.
1. Из целого кадра выделить только лицо
2. Распознать это лицо.

Использование библиотеки OpenCV на сервере Умного Дома
Определение на фото лиц с помощью PHP и библиотеки OpenCV
Только половина дела...

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

Для решения этой задачи мы воспользуемся библиотекой OpenCV (компьютерное зрение). Эта библиотека позволяет в том числе выявить на фотографии лица.

Установка OpenCV на Linux (Debian Squeeze)

Прежде всего, необходимо установить пакеты, которые нужны для компиляции библиотеки.

apt-get install build-essential cmake pkg-config libjpeg62-dev
apt-get install libtiff4-dev libv4l-dev libpng++-dev libavcodec-dev
apt-get install libavformat-dev libswscale-dev libdc1394-22-dev
apt-get install libgstreamer0.10-dev libgtk2.0-dev

Теперь скачаем с официального сайта релиз OpenCV 2.3.1 и распакуем его

tar -xvjf OpenCV-2.3.1a.tar.bz2

Заходим в распакованную папку и создаем новый каталог release, а затем компилируем и устанавливаем библиотеку.

make release
cd release
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_EXAMPLES=ON ..
make
make install

Программы с использованием OpenCV могут быть написаны на любом языке, но мне удобнее набросать скрипт на языке PHP, поэтому я установил PHP-модуль facedetect, работающий с OpenCV. Для использования в системе PHP и Apache нужно, чтобы были установлены следующие пакеты apache2, php5, php5-dev php5-gd

Качаем с Github PHP-Facedetect, распаковываем и устанавливаем с помощью нехитрой процедуры:

tar -xvzf infusion-PHP-Facedetect.tar.gz
phpize
./configure
make
make install

Теперь осталось только в файле php.ini подключить установленный модуль.

extension=facedetect.so

Прежде чем написать простенькую программу, нужно еще раз немного подумать. Для нейронной сети нам нужно подготовить как можно более нормализованные примеры, чтобы сеть не отвлекалась на мелочи, которые не имеют к решению нашей задачи никакого отношения. Поэтому необходимо предусмотреть две вещи:
Первое. Лицо на фотографии может занимать разную площадь, в том числе в пикселях. Значит необходимо произвести ресайз всех изображений до определенного формата, например 200 на 200 точек.
Второе. Цвет. В данном случае цвет будет мешать. Эта та информация, которая в целом не несет с точки зрения классификации и распознавания лиц полезной функции, но может теоретически мешать нейронной сети правильно принять решение. Мы должны преобразовать цветную фотографию в черно-белую (а точнее, в grayscale).

Сделать это нетрудно и в результате получается вот такой скрипт.

<?
$face = face_detect("snap.jpg",'haarcascade_frontalface_alt.xml');
$im = @imagecreatefromjpeg("snap.jpg");
$crop  = @imagecreatetruecolor(200, 200);
imagecopyresampled($crop, $im, 0, 0, $face[0]['x'], $face[0]['y'], 200, 200, $face[0]['w'], $face[0]['h']);

imagefilter($crop, IMG_FILTER_GRAYSCALE);
imagejpeg($crop, "face.jpg", 100);

imagedestroy($crop);
imagedestroy($im);
?>

Программа анализирует snap.jpg, полученный с камеры наблюдения, выявляет на фото лицо и записывает в файл face.jpg

Обработка фото для распознания лица
В результате из целого кадра получаем grayscale кроп 200х200 готовый к распознаванию

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

$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=0; $y<200; $y++)
            {
                for($x=0; $x < 200; $x++)
                {
                    $rgb = imagecolorat($im, $x, $y) / 16777215;
                    $cur_array[$cnt] = $rgb;
                    $cnt++;
                    //echo $rgb."<br>";;
                }
            }

            imagedestroy($im);
            $my_example[$j] = array($cur_array, array($i));
            $j++;
        }

    }
}

$ann = fann_create(array(40000, 200, 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");

Теперь проверим работоспособность сети в боевых условиях и с помощью программы.

$ann = fann_create("my.ann");
$file_cnt = 0;

$im = imagecreatefromjpeg("../snap/Camera1.jpg");

$cur_array = array();
$cnt = 0;
for($y=0; $y<200; $y++)
{
    for($x=0; $x < 200; $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.7 будут говорить, что этому человеку разрешен доступ. Значения меньше 0.3 - нет. Иные значения лучше трактовать как неопределенные. Фотографии таких лиц лучше складывать в отдельную папку для дальнейшего дообучения сети.

Испытания в реальных условиях показали, что предложенный подход неплохо справляется с задачей.
Человек, который имеет доступ. Ответ нейронной сети: [0] => 0.960845589638
Человек, у которого нет доступа. Ответ нейронной сети: [0] => 0.0223079491407

У предложенного в статье решения есть только один минус. Время распознавания. Оно зависит от объема обучающего материала. В моем примере для обучения использовалось 40 фотографий. Объем сети в памяти занимает порядка 260Мб. Время распознавания на компьютере с процессором Pentium 4 3ГГц - около 15 секунд. Но, полагаю, если система покажет свою работоспособность в будущем, можно будет подумать и об апгрейде сервера. Дообучать сеть можно будет в полуавтоматическом режиме.

Вот такой вот получился фейс-контроль.

Автор: Andrey_B
Любое использование материалов сайта возможно только с разрешения автора и с обязательным указанием источника.



Добавить комментарий:



Сортировка комментариев: Последние сверху | Первые сверху

2015-08-12 00:17:45 | Алексей
Что если усложнить задачу: 3. Выдать информацию о лице (имя файла, с которым совпадает лицо). Реально?


2014-12-26 11:43:49 | Валерий
Спасибо, установил.
Все равно черный квадрат.


2014-12-25 12:37:49 | Andrey_B
Валерий, правильное имя пакета "libv4l-dev".


2014-12-25 10:17:46 | Валерий
1. Не удалось найти пакет lib4vl-dev.

2. По первому примеру, все проходит без ошибок, но файл face.jpg просто черный квадрат

Может быть черный квадрат из за того, что lib4vl-dev не установлен?


2014-02-02 15:53:00 | Alexander
Мне также первым в голову пришла идея с фотографией вместо головы владельца. Система у вас отличает фото от живого человека? Догадаюсь: ответ будет, скорее всего, ниже 0,3 :)


2013-09-24 18:22:44 | Arbuzmaster
Подскажите пожалуйста почему в fann_train($ann, $my_example, 1000, 0.001, 1000) 5 параметров хотя ожидалось всего 3 ? libFann 2.1.0


2013-01-20 15:21:15 | Stas
Запускаю скрипт определения скрипта и получаю
$ php face-detect.php
PHP Fatal error: Call to undefined function face_detect() in /home/stas/Workplace/smarthouse/face-detect.php on line 2

хотя
find /usr/ -name facedetect.so
/usr/src/PHP-Facedetect-master/.libs/facedetect.so
/usr/src/PHP-Facedetect-master/modules/facedetect.so
/usr/lib/php5/20090626+lfs/facedetect.so

и
tail -2 /etc/php5/apache2/php.ini
extension=fann.so
extension=facedetect.so

Почему так?


2012-04-02 13:15:46 | Andrey_B
Валерий, вы неправильно обучаете сеть, потому что неправильно заполняете массив $my_example. У вас там какое-то шаманство.
Заполняться он должен примерно так:
Для $i = 0
$my_example[$j] = array($cur_array, array(0,0,0)
Для $i = 1
$my_example[$j] = array($cur_array, array(0,0,1)
Для $i = 2
$my_example[$j] = array($cur_array, array(0,1,0)
Для $i = 3
$my_example[$j] = array($cur_array, array(1,0,0)
Собственно, порядок тут неважен. Главное чтобы при трактовке результатов вы пользовались той же логикой. В PHP этот кусом можно реализовать покороче.
А вообще для того рода обсуждений лучше воспользуйтесь нашим форумом. Там удобнее.


2012-04-02 10:58:17 | Valeriy
Попробовал реализовать задачу аналогичную той, что описал stpavel, только с людьми. Вот так немного изменил обучающий скрипт:
====
$j = 0;
$my_example = array();
for ( $i = 0; $i < 4; $i++ )
{
if ($i == 0)
{
$l = 0;
$index = array(0, 0, 0);
}
else
{
$l = $i;
$l--;
$index = array(0, 0, 0);
$index[$l] = 1;
}
$d = dir("teach/$i");
while($entry = $d->read())
{
if ( preg_match("/jpg/", $entry) )
{
$im = imagecreatejpeg("teach/$i/$entry");

$cur_array = array();
$cnt = 0;
for($y=0; $y<200; $y++)
{
for($x=0; $x < 200; $x++)
{
$rgb = imagecolorat($im, $x, $y) / 16777215;
$cur_array[$cnt] = $rgb;
$cnt++;
/ echo $rgb."
";;
}
}

imagedestroy($im);
/ $index[$l] = array($cur_array, array($l));
if ( $l = 0 )
{
$my_example[$j] = array($cur_array, array($l));
}
else
{
/ $my_example[$j] = array($cur_array, array($index));
$j++;
}

}
}

$ann = fann_create(array(40000, 200, 3), 1.0, 0.7);
if ( fann_train($ann, $my_example, 1000, 0.001, 100) == FALSE)
exit('Could not train $ann.');

fann_save($ann, "my1.ann");
?>
====
Т.е. изменил маркировку массива my_example. Каждый элемент этого массива маркировался 0 или 1, а теперь 000, 100, 010, 001 (у меня 4 папки: в первой (которая "0") чужие фото, и 3 со "своими" (1, 2 и 3). На выходе хочется получить что-то типа:
0,9
0,2
0,3
Т.е. человек опознан, и он из папки 1. Но на практике работает не так. Даже при обучении все время выдает разные коэффициенты, а результат выполнения скрипта распознавания разный на одной и той же фотографии при переобучении программы без добавления новых фото(((. Может я недочитал/недопонял принцип работы и логику FANN? Вобщем, если есть идея где я ошибся, буду рад помощи.
P.S.: сори за предыдущий комментарий, некорректно добавился.


2012-03-27 10:46:16 | Andrey_B
Debian 5 - это Lenny?
У меня libfann1 прекрасно установился.
Подробнее здесь


2012-03-27 01:46:41 | artmel
Огромное спасибо за такие статьи!

Подскажите, стоит дебиан 5 , не смог поставить fannlib1, только fannlib2
и теперь у меня выбивает
/var/neuro php index.php
/etc/php5/modules/fann.so: undefined symbol: fann_create_array

как можно это победить? или как поставить fannlib1 ?


2012-01-21 23:49:48 | Andrey_B
Никита, может быть и проще. Нужно будет попробовать.


2012-01-19 15:28:26 | Никита
А не проще ли было воспользоваться распознованием лиц с помощью opencv (opencv.willowgarage.com/wiki/FaceRecognition)? в моей базе 5 лиц, на старой машинке (coreduo, интегрир. видео) отрабатывает разпознование немногим больше секунды.


2011-12-23 14:24:25 | DMG
Александр, тепла или открытого пламени? Если тепла то смотрите PIR-датчики, из готового Фотоны всякие...


2011-12-21 10:57:24 | Andrey_B
red, скажите, а вы вообще-то читали статью?


2011-12-21 01:53:07 | red
А если, к примеру, такой случай: я не имею доступ, то есть ваша нейронная сеть меня не знает, а ВАС ваша нейронная сеть знает и естественно любезно откроет ВАМ дверь. Но я в свою очередь имею возможность сфотографировать ВАС, а затем поднести ВАШУ фотографию к камере видео наблюдения. Тогда получается она впустит меня! Как с этим быть!??


2011-10-31 17:56:21 | Александр
Уважаемый Andrey_B, не встречались ли вам бюджетные решения тепловых сенсоров?
Основная идея такая: при попадании человека или другого источника тепла туда, где ему быть нельзя, включается видеозапись с камеры расположенной рядом и умный дом реагирует на это. А дальнейшее уже зависит от вашего желания, как он вам сообщит об этом.Хоть Фотографию пошлет..
Есть ли подобные решения с адекватным ценником? А то уж больно нехорошая цена на промышленно исполненные системы существует.


2011-10-18 14:25:19 | Дмитрий
Это бесподобно! ) Автор молодец!
Сам пытался подружить OpenCV с Java, в среде NetBeans,
пока ничего путёвого не вышло, похоже всё-таки руки кривые )))
Как появится свободное время обязательно займусь!!