Rating@Mail.ru

Форум по операционной системе GNU/Linux и свободному программному обеспечению


Текущее время: 18 дек 2017, 12:11

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 26 ]  На страницу Пред.  1, 2, 3
Автор Сообщение
 Заголовок сообщения: Re: OpenCV и компьютерное зрение
Непрочитанное сообщениеДобавлено: 08 июл 2017, 16:46 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10265
Откуда: Харьков
Olej писал(а):
Подборку буду продолжать...

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

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


Вложения:
b2.jpg
b2.jpg [ 70.85 КБ | Просмотров: 157 ]
b3.png
b3.png [ 204.43 КБ | Просмотров: 157 ]
Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: OpenCV и компьютерное зрение
Непрочитанное сообщениеДобавлено: 09 июл 2017, 15:40 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10265
Откуда: Харьков
Olej писал(а):
То, что рассматривается в этой теме - только малая часть подобных задач: детектирование компрометации изображения - когда видеокамере подсовывают не собственное лицо, а зафиксированную картинку другой персоны на листе бумаги или, что ещё более актуально, на экране смартфона или планшета.

Суть не в конкретике такой задачи, а в той мощи, которую уже предоставляет проект OpenCV (которая, мощь, оказалась и для меня неожиданной при детальном использовании :-o ) и который проект весьма динамично развивается.

А если коротко отвлечься на конкретную задачу, чтобы к этому больше не возвращаться, а она сама достаточно интересная: нужно детектировать рамку вокруг лица, при том, что она может быть местами разорвана или искажена другим образом.
Можно бы строить нейронный обучаемый классификатор (как, например, придаваемые классификаторы для изображения лица) ... но нужно хорошо отдавать себе отчёт что это потребует: многие тысячи изображений, разделённые на "да" и "нет" и несколько десятков часов машинного времени на обучение (это по описанию опыта тех, кто это проделывал).
Мы пошли другим путём - построить логическую алгоритмику ... которая в результате сотен экспериментов, методом проб и ошибок, последовательными шагами свелась к следующему (что как оказалось тоже достаточно громоздко):
- Алгоритмом LSD (который описан в сообщении от 04 ноя 2016) на изображении строятся отрезки линий...
- Поскольку линии на изображении можно выделять только по градиентам яркости (что и делает LSD) и результаты вероятностные, 1-м шагом отсеиваются (по порогу) линии с сомнительной вероятностью, алгоритм LSD как-раз формирует параметр NFA (Number of False Alarms) для каждого отрезка
- Классификатором определяется область лица (это типовая задача OpenCV), можем считать что это 2D координата центра + некоторый характеристический радиус ... отрезки попадающие внутрь этой области отфильтровываются...
- Вычисляются углы наклона каждого отрезка, для этого удобно далее оперировать со всеми координатами отрезков как с комплексными значениями на 2D плоскости
- Угловые координаты из диапазона (0...2*π) или (-π ...+π) приводятся к диапазону (0...π) — для отрезков 3-го и 4-го квадрантов меняется ориентация начало-конец - это потому, что для наших целей отрезки с наклонами 45, 225, или -135 градусов - идентичны, они параллельны, и рассматривать их раздельно нельзя.
- Следующим критерием отсечения является критерий: отрезок должен лежать в пределах сектора раскрыва из точки центра, вокруг нормали к отрезку, проведенной из этой точки. Проще этот критерий можно сформулировать качественно: отрезок или любое его продолжение не должен проходить через область изображения (или немного расширенную область изображения, умноженную на некоторый коэффициент). Этим отбраковываются радиальные отрезки, ориентированные не вокруг изображения (должны окружать его), а направленные на него. Только введение такой фильтрации позволило избавиться от достаточно частого (показали тестовые прогоны) эффекта «рукав»:
Вложение:
br.png
br.png [ 145.02 КБ | Просмотров: 154 ]

Или, наоборот, клетчатая рубашка может набросать столько отрезков линий, что они без такой фильтрации скомпрометируют любое изображение:
Вложение:
okl.png
okl.png [ 225.61 КБ | Просмотров: 154 ]

- Следующим этапом все отрезки по углу ориентации кластеризуются (раскладываются) по N угловым кластерам, N — параметр алгоритма, который может меняться в очень широких пределах (6...25), каждый кластер имеет угловой размер ψ=(180/N)ο, причём 1-й кластер — это горизонталь (-ψ/2...+ψ/2). Это и следующий п.9 делается для борьбы с вращением изображения. Вращение можно ожидать в пределах от -45 до +45 градусов , т. е., вообще то говоря, на любой произвольный угол. Мы не можем оперировать такими понятиями как «вертикаль», «горизонталь» в определении направлений!
Вложение:
bvr.png
bvr.png [ 152.32 КБ | Просмотров: 154 ]

- Дальше нужно выделить 2 доминантных кластера, представляющих 2 ортогональных направления рамки (это будут координатные оси разыскиваемой рамки ... но это не обязательно 90 градусов). Это связано с тем, что:
а). использовать строго горизонталь и вертикаль для этого нельзя: при вращениях рамки по или против часовой стрелки;
б). использовать строго 90 градусов между кластерами для выбора ортогональных направлений нельзя: при диагональных наклонах рамки (как в аксонометрии):
Вложение:
baks.png
baks.png [ 158.72 КБ | Просмотров: 154 ]

- Выделяются 2 кластера с преобладающей суммой длин отрезков, принадлежащих кластеру (как вариант алгоритма — просто число отрезков принадлежащих кластеру). Это делается рекурсивным 2-х мерным (по номерам кластеров) поиском (при N=10, например, это требует сравнения 100 попарных гипотез: как вариант, для каждой пары кластеров сумма (длин отрезков, числа отрезков) умножается на sin() угла между централями кластеров, и отбирается пара с максимальным таким значением. Эти 2 преобладающих ортогональных направления остаются для дальнейшего распознавания (оси координат), все отрезки остальных кластеров отбрасываются.
- Дальше делается консолидация детектированных отрезков внутри каждого из 2-х доминантных кластеров: если конец m-го отрезка отстоит от начала m+1-го на некоторый небольшой радиус (это ещё один параметр алгоритма) в смысле евклидовой метрики между координатами, то они объединяются в один, более длинный, отрезок (начало от отрезка m и концом от отрезка m+1). Этот процесс над всеми отрезками кластера нужно выполнять циклически неоднократно (2-3 прохода), до тех пор, пока пригодных для объединения отрезков не останется. Это очередной этап фильтрации отрезков, который позволяет их число сократить на порядок.
Это процесс, в принципе, неоднозначный, в зависимости от того, с какого отрезка начинать консолидацию.
- Дальше оценивается по каждому из 2-х доминантных кластеров асимметрию рассеивания распознанных участков относительно прямоугольника изображения: подсчитывается число отрезков в кластере левее-правее или выше-ниже области изображения лица (как вариант, возможно более правильный — не просто число, а сумма длин отрезков). Т.е. общее число отрезков в кластере n делится на 2 части: «до» и «после» лица, n1+n2=n. Асимметрия затем оценивается как отношение средне-геометрического к средне-арифметическому: А = (n1*n2) / ((n1 + n2)/2) / ((n1 + n2)/2) (можно и извлечь корень квадратный, но это ничего не добавит в смысле распознавания). Эта величина лежит в пределах [0...1] (1 при абсолютно симметричном расположении линий — признак компрометации, 0 — при полной асимметрии, отсутствии компрометации по этой оси). Вот здесь (специально подобранное изображение) нет рамки, поскольку нет асимметрии по вертикали:
Вложение:
or.png
or.png [ 525.72 КБ | Просмотров: 154 ]

- Конечный критерий компрометации (рамки) оценивается как произведение асимметрии по 2-м доминирующим координатам А = A1 * A2.
- Дискриминация пороговая: для изображения без рамки предполагается A=0 или меньше некоторого небольшого (0.1, 0.2, ...) порога (это ещё один параметр алгоритма); для изображения в рамке A>0 (или порога).


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: OpenCV и компьютерное зрение
Непрочитанное сообщениеДобавлено: 09 июл 2017, 16:21 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10265
Откуда: Харьков
А теперь собственно к коду...
Цитата:
Алгоритмом LSD (который описан в сообщении от 04 ноя 2016) на изображении строятся отрезки линий...

Код алгоритма LSD взят в неизменном виде, так как он создан его авторами.
Он создаёт набор обнаруженных отрезков в файл.
Алгоритм LSD включён в состав OpenCV версий 3.Х ... но в репозиториях Linux дистрибутивов представлены версии OpenCV версий 2.Х.
Нет большой проблемы сборки OpenCV версий 3.Х из исходников, но не хотелось этого делать на каждом месте демонстрации у заказчика, поэтому использовалась авторская версия LSD, которая во всех других программах запускалась как дочерний процесс.
Алгоритм LSD формирует построчно характеристики детектированных отрезков, примерно как-то так:
Код:
...
[  65.984:   0.555,  64.027:  60.654]     60.131          91.865
[ 100.560:  54.894, 109.328:  56.000]      8.838           7.187
[  51.092:  13.057,  47.816:  50.707]     37.792          94.972
[  47.931:  51.742,  39.255: 145.614]     94.272          95.281
[ 108.107:  61.175,  69.319:  62.147]     38.800         178.565
[  93.187:  51.101,  76.568:  53.258]     16.758         172.605
[ 129.553: 159.235, 140.975: 170.262]     15.876          43.992
...

Здесь первые 4 числа - это complex представление координат начала и конца линии, а последнее - это -log10(NFA), NFA - вероятность ложной тревоги, число 17, например, соответствует значению NFA = 10^(-17), а число 1 — NFA = 0.1. NFA ... отрезки с малыми значениями этого последнего параметра могут быть шумом детектирования, могут отбрасываться.

Дочерний процесс LSD во всех приложениях запускает одна функция (чтобы всё было единообразно) discriminate(), которая и формирует конечное численное значение A (компрометации). Останавливаться подробнее не буду, функция реализует тот многошаговый алгоритм который описан выше ... если кому понадобится - загляните в код. Это не относится собственно к OpenCV, о котором тема ... и не сильно интересно.


Вложения:
lsd_1.6.tgz [588.96 КБ]
Скачиваний: 4
discriminate.h [1.51 КБ]
Скачиваний: 4
discriminate.cc [22.44 КБ]
Скачиваний: 3
Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: OpenCV и компьютерное зрение
Непрочитанное сообщениеДобавлено: 09 июл 2017, 16:54 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10265
Откуда: Харьков
Olej писал(а):
А теперь собственно к коду...
...
Это не относится собственно к OpenCV, о котором тема ... и не сильно интересно.

А вот сами приложение - они демонстрируют мощь OpenCV:

1. lsd2f.cc - программа чтения файлов изображений и их распознавания
Программе в качестве параметров можно передать сколько угодно изображений и она их оценивает + делает хронометраж времени распознавания. Как-то так (показаны будут только ключевые строки кода - чтоб только представить как это выглядит в OpenCV):
Код:
   struct timeval tmb, tme;
   for( int i = optind; i < argc; i++ ) {
      cout << "file: " << argv[ i ] << endl;
      gettimeofday( &tmb, NULL );
      float discr = discriminate( argv[ i ], false, nclu, rad, min );
      gettimeofday( &tme, NULL );
      float intv = (float)( tme.tv_sec - tmb.tv_sec ) * 1.E6 +
                   (float)( tme.tv_usec - tmb.tv_usec );
      s1 += intv;
      s2 += intv * intv;
      if( discr < 0 ) continue;                 // нет идентификации лица
      if( image_level ) {
         cout << "press space to continue..." << endl;
         while( (char)waitKey( 100 ) != ' ' );
      }
   }
   int n = argc - optind;
   s1 /= n;
   s2 = s2 / n - s1 * s1;
   cout << "processed " << n << " images, mean time was " << round( s1 );
   if( n > 1 )
     cout << " +/- " << round( sqrt( s2 ) ) << "(" << round( sqrt( s2 ) ) / s1 * 100 << "%)";
   cout << " mksec." << endl;


2. voline.cc — программа покадрового чтения изображений из видеокамеры или видеофайла.
Код:
   if( optind == argc ) help( *argv, ERR_NO_ARGS );
   else if( optind + 1 == argc )
      sprintf( command, "./vistream %s", argv[ optind ] );
   else
      sprintf( command, "./vistream %s %s", argv[ optind ], argv[ optind + 1 ] );
   FILE *pipe = popen( command, "r" );
   if( !pipe )
      terminate( ERR_EXEC_PIPE, command );
   double s1 = 0.0, s2 = 0.0;
   struct timeval tmb, tme;
   int n = 0;
   while( true ) {
      char imgname[ 80 ];
      if( NULL == fgets( imgname, sizeof( imgname ), pipe ) ) break;
      *strrchr( imgname, '\n' ) = '\0';
      cout << "save file: " << imgname << endl;
      gettimeofday( &tmb, NULL );
      discriminate( imgname, true, nclu, rad, min ); // << endl;
      gettimeofday( &tme, NULL );
      float intv = (float)( tme.tv_sec - tmb.tv_sec ) * 1.E6 +
                   (float)( tme.tv_usec - tmb.tv_usec );
      s1 += intv;
      s2 += intv * intv;
      n++;
   }

Программа voline для захвата видеопотока использует дочерний процесс vistream.cc
Код:
   VideoCapture capture;
   bool res = argc > 2 ? capture.open( argv[ 2 ] ) : capture.open( 0 );
   if( !res ) {
      cerr << "ERROR: can't video capture" << endl;;
      return 1;
   }
   string window_name = "space - video | q or esc - quit";
   cerr << "press space to save a picture. q or esc to quit" << endl;
   namedWindow( window_name, WINDOW_NORMAL ); //resizable window;
   Mat frame, gray;
   int n = 0;
   res = true;
   while( res ) {
      capture >> frame;
      if( frame.empty() ) break;
      cvtColor( frame, gray, COLOR_BGR2GRAY );
      imshow( window_name, gray );
      char key = (char)waitKey( 30 );         //delay N millis, usually long enough to display and capture input
      switch ( key ) {
         case 'q':
         case 'Q':
         case 27:                             //escape key
            res = false;
            break;
         case ' ':                            //save an image
            sprintf( filename, "%s%.3d.pgm", ftitle, ++n );
            imwrite( filename, gray );
            cout << filename << endl;
            break;
         default:
            break;
      }
   }

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

3. avtest.cc — программа оценивания в видеопотоке из видеокамеры или видеофайла.
Здесь, наоборот, оценивание происходит непрерывно, в потоке, а результат отображается рамкой окна изображения:
- зелёная - изображение ОК, не компрометированное
- красная - обнаружена прямоугольная рамка
- прозрачная, нет рамки - не обнаруживается изображение лица в кадре
Код:
...
   char *tmpname = optind != argc ? argv[ optind ] : (char*)"/dev/shm/image.pgm";
   if( !strrchr( tmpname, '.' ) )
      strcat( tmpname, ".pgm" );
   else if( strcmp( strrchr( tmpname, '.' ), ".pgm" ) != 0 )
      terminate( ERR_IMG_FILE, tmpname );
   VideoCapture capture;
   bool res = strlen( videoname ) != 0 ? capture.open( videoname ) : capture.open( 0 );
   if( !res ) terminate( ERR_VID_CAPT );
   cout << "press q or esc to quit" << endl;
   Mat frame, gray;
   string window_name = "press q or esc to quit";
   double s1 = 0.0, s2 = 0.0;
   struct timeval tmb, tme;
   int n = 0, ni = 0, nc = 0, nr = 0;
   while( true ) {
      capture >> frame;
      if( frame.empty() )
         break;
      cvtColor( frame, gray, COLOR_BGR2GRAY );
      if( !imwrite( tmpname, gray ) )
         terminate( ERR_IMG_WRITE, tmpname );
      gettimeofday( &tmb, NULL );
      float disc = discriminate( tmpname, true, nclu, rad, min );
      gettimeofday( &tme, NULL );
      float intv = (float)( tme.tv_sec - tmb.tv_sec ) * 1.E6 +
                   (float)( tme.tv_usec - tmb.tv_usec );
      s1 += intv;
      s2 += intv * intv;
      n++;
      namedWindow( window_name, WINDOW_NORMAL ); //resizable window;
      Rect border( Point( 0, 0 ), frame.size() );
      const float limit = 0.05;
      if( disc >= 0.0 ) {
         rectangle( frame, border,
                    ( disc > limit ? Scalar( 0, 0, 255 ) : Scalar( 0, 255, 0 ) ),
                    5 );
         if( disc > limit )
            nc++;
         else
            nr++;
      }
      else
         ni++;
      imshow( window_name, frame );
      char key = (char)waitKey( 30 );
      if( 'q' == key || 'Q' == key || 27 == key )
         break;
   }
   capture.release();
...


Вложения:
lsd2f.cc [3.53 КБ]
Скачиваний: 3
voline.cc [2.74 КБ]
Скачиваний: 2
vistream.cc [1.46 КБ]
Скачиваний: 4
avtest.cc [4.2 КБ]
Скачиваний: 4
Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: OpenCV и компьютерное зрение
Непрочитанное сообщениеДобавлено: 09 июл 2017, 16:58 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10265
Откуда: Харьков
Olej писал(а):
Olej писал(а):
А теперь собственно к коду...

А вот сами приложение - они демонстрируют мощь OpenCV:

Всё что выше показано - показано в качестве наброска, подсказки: как использовать библиотеки OpenCV компьютерного зрения.
А сам проект (всё что нужно для сборки!) может быть взят в этом архиве.
Тестовые файлы видеозахвата, на которых отрабатывалось, не привожу - они слишком большие, по 80-200Mb.
У меня это были файлы формата Matroska (.mkv), могут быть и .avi ... ещё что-то, что поддерживает OpenCV, а поддерживает он (на уровне совместимости и форматов) много.
Если кого заинтересуют подобные задачи - сами нарежете с WEB-камеры тестов.

P.S. 15 в имени файла архива - это номер версии, которые менялись при передаче заказчику, раз в 2 недели или месяц ... т.е. можете прикинуть, что здесь довольно много работы. ;-) Тем не менее, без OpenCV это было бы просто чудовищно много, неподъёмно...


Вложения:
pro015.tgz [1.75 МБ]
Скачиваний: 4
Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: OpenCV и компьютерное зрение
Непрочитанное сообщениеДобавлено: 09 июл 2017, 23:56 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10265
Откуда: Харьков
Olej писал(а):
А сам проект (всё что нужно для сборки!) может быть взят в этом архиве.

Эта часть темы (2017-го года) показана, главным образом, для того, чтобы показать, а это видно, как кажется, даже беглым взглядом, насколько мощным на сегодня является проект OpenCV.
Та лёгкость, с которой он:
- обрабатывает изображения в самых разнообразных графических форматах...
- захватывает видеопоток с одинаковым успехом хоть из файла (самых разных видеоформатов), хоть из USB WEB-камер (хоть одной, хоть нескольких)...
- и то, как из этих видеопотоков выхватываются всё эти, опять же, кадры изображений.


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 26 ]  На страницу Пред.  1, 2, 3

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB
[ Time : 0.319s | 19 Queries | GZIP : On ]