Распознавание образов для программистов

ВНИМАНИЕ! БЛОГ ПЕРЕЕХАЛ ПО АДРЕСУ
RECOG.RU

25 Май 2010

28. Слежение за точками

написано в рубрике: OpenCV — Кручинин Александр @ 10:33 ДП

Пример организации слежения за точками представлен в файле lkdemo.c в разделе samples (OpenCV). Попробовав запустить пример, вы увидите изображение с предварительно подключённой вами камеры. Нажмите мышкой, к примеру, на вашем носу – появится точка, которая будет отслеживаться компьютером при вашем движении лицом. Программой используется алгоритм Lucas-Kanade. В листинге 28.1 приведён текст примера с комментариями на русском языке.

Листинг 28.1

ifdef _CH_

#pragma package <opencv>

#endif

 

#define CV_NO_BACKWARD_COMPATIBILITY

 

#ifndef _EiC

#include “cv.h”

#include “highgui.h”

#include <stdio.h>

#include <ctype.h>

#endif

 

IplImage *image = 0, *grey = 0, *prev_grey = 0, *pyramid = 0, *prev_pyramid = 0, *swap_temp;

 

int win_size = 10;

const int MAX_COUNT = 500;

CvPoint2D32f* points[2] = {0,0}, *swap_points;

char* status = 0;

int count = 0;

int need_to_init = 0;

int night_mode = 0;

int flags = 0;

int add_remove_pt = 0;

CvPoint pt;

 

//обработка событий с мыши

void on_mouse( int event, int x, int y, int flags, void* param )

{

    if( !image )

        return;

 

    if( image->origin )

        y = image->height – y;

 

    if( event == CV_EVENT_LBUTTONDOWN )

    {

            //Если нажали левую кнопку мыши, то добавляем отслеживаемую точку

        pt = cvPoint(x,y);

        add_remove_pt = 1;

    }

}

 

 

int main( int argc, char** argv )

{

    CvCapture* capture = 0;

 

      //Получаем видеопоток с камеры или видеофайла, в зависимости от входных параметров

    if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))

        capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] – ‘0′ : 0 );

    else if( argc == 2 )

        capture = cvCaptureFromAVI( argv[1] );

 

    if( !capture )

    {

        fprintf(stderr,”Could not initialize capturing…\n”);

        return -1;

    }

   

      //Печатается приветствие и краткий хелп по программе

    printf (”Welcome to lkdemo, using OpenCV version %s (%d.%d.%d)\n”,

          CV_VERSION,

          CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);

 

    printf( “Hot keys: \n”

            “\tESC – quit the program\n”

            “\tr – auto-initialize tracking\n”

            “\tc – delete all the points\n”

            “\tn – switch the \”night\” mode on/off\n”

            “To add/remove a feature point click it\n” );

 

    cvNamedWindow( “LkDemo”, 0 );

      //Устанавливаем функцию обработчик мыши, сама функция находится выше

    cvSetMouseCallback( “LkDemo”, on_mouse, 0 );

 

      //Главный рабочий цикл программы – работает бесконечно, пока вы принудительно его не закроете, например нажав ESCAPE

    for(;;)

    {

        IplImage* frame = 0;

        int i, k, c;

 

            //Получаем фрейм из видеопотока

        frame = cvQueryFrame( capture );

        if( !frame )

            break;

 

        if( !image )

        {

            /*Если изображение image не создано, то надо распределить все буферы. Изображение не создано первоначально,

                  поэтому это всего навсего инициализация.

                  */

            image = cvCreateImage( cvGetSize(frame), 8, 3 );

            image->origin = frame->origin;

            grey = cvCreateImage( cvGetSize(frame), 8, 1 );

            prev_grey = cvCreateImage( cvGetSize(frame), 8, 1 );

            pyramid = cvCreateImage( cvGetSize(frame), 8, 1 );

            prev_pyramid = cvCreateImage( cvGetSize(frame), 8, 1 );

                  //Выделяем массивы под точки, судя по MAX_COUNT максимально у нас может быть 500 точек

            points[0] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));

            points[1] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));

            status = (char*)cvAlloc(MAX_COUNT);

            flags = 0;

        }

 

            //копирование и перевод в чёрно-белое изображение

        cvCopy( frame, image, 0 );

        cvCvtColor( image, grey, CV_BGR2GRAY );

 

            //Это для эффекта, когда вы нажимаете n изображение становится тёмным и вы видите только перемещающиеся

            //назначенные вами точки

        if( night_mode )

            cvZero( image );

 

        if( need_to_init )

        {

            //Это нужно для автоматической инициализации наблюдения – если вам лень тыкать мышкой, то можно

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

            IplImage* eig = cvCreateImage( cvGetSize(grey), 32, 1 );

            IplImage* temp = cvCreateImage( cvGetSize(grey), 32, 1 );

            double quality = 0.01;

            double min_distance = 10;

 

            count = MAX_COUNT;

                  //определяет наиболее “сильные” углы изображения

            cvGoodFeaturesToTrack( grey, eig, temp, points[1], &count,

                                   quality, min_distance, 0, 3, 0, 0.04 );

                  //уточняет местоположение углов

            cvFindCornerSubPix( grey, points[1], count,

                cvSize(win_size,win_size), cvSize(-1,-1),

                cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));

                  //удаляет ненужные изображения

            cvReleaseImage( &eig );

            cvReleaseImage( &temp );

 

            add_remove_pt = 0;

        }

        else if( count > 0 )

        {

                  //Если есть хотя бы одна точка на экране, то за ней надо следить

 

                  //Вычисляем оптический поток на факт поиска особенностей

                  //points[0] – предыдущие точки points[1] – текущие точки

            cvCalcOpticalFlowPyrLK( prev_grey, grey, prev_pyramid, pyramid,

                points[0], points[1], count, cvSize(win_size,win_size), 3, status, 0,

                cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03), flags );

            flags |= CV_LKFLOW_PYR_A_READY;

                  //перебираем все точки

            for( i = k = 0; i < count; i++ )

            {

                        //Если вы добавили новую точку нажатием мыши и она слишком близка к предыдущей – просто удаляем её

                if( add_remove_pt )

                {

                    double dx = pt.x – points[1][i].x;

                    double dy = pt.y – points[1][i].y;

 

                    if( dx*dx + dy*dy <= 25 )

                    {

                        add_remove_pt = 0;

                        continue;

                    }

                }

 

                if( !status[i] )

                    continue;

 

                points[1][k++] = points[1][i];

                        //Отображаем точку на экране

                cvCircle( image, cvPointFrom32f(points[1][i]), 3, CV_RGB(0,255,0), -1, 8,0);

            }

            count = k;

        }

 

        if( add_remove_pt && count < MAX_COUNT )

        {

                  //Если точка прошла процедуру проверки (см. выше), то добавляем её в буфер

            points[1][count++] = cvPointTo32f(pt);

                  //уточняет местоположение углов для всех точек

            cvFindCornerSubPix( grey, points[1] + count – 1, 1,

                cvSize(win_size,win_size), cvSize(-1,-1),

                cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));

            add_remove_pt = 0;

        }

 

        CV_SWAP( prev_grey, grey, swap_temp );

        CV_SWAP( prev_pyramid, pyramid, swap_temp );

            //Меняем местами точки – новые становятся старыми на следующем шаге цикла

        CV_SWAP( points[0], points[1], swap_points );

        need_to_init = 0;

        cvShowImage( “LkDemo”, image );

 

        c = cvWaitKey(10);

        if( (char)c == 27 )

            break;

        switch( (char) c )

        {

        case ‘r’:

            need_to_init = 1;

            break;

        case ‘c’:

            count = 0;

            break;

        case ‘n’:

            night_mode ^= 1;

            break;

        default:

            ;

        }

    }

 

    cvReleaseCapture( &capture );

    cvDestroyWindow(”LkDemo”);

 

    return 0;

}

 

#ifdef _EiC

main(1,”lkdemo.c”);

#endif

 

Итак, запускаем пример и ставим на ручке точку (Рис. 28.1)

Рис. 28.1

Рис. 28.1

Следим за точкой, перемещая ручку (Рис. 28.2).

Рис. 28.2

Рис. 28.2

 

Для пущего эффекта, нажимаем ‘n’ и смотрим за перемещением точки на чёрном экране (Рис. 28.3).

 

Рис. 28.3

Рис. 28.3

 

Подробнее о параметрах функций для слежения поговорим в другой раз.

Нет комментариев

Еще нет комментариев.

RSS лента комментариев к этой записи.

Извините, комментирование на данный момент закрыто.

Работает на WordPress