Перейти к содержимому
Compvision.ru
Smorodov

Распознавание лиц HMM (Скрытые марковские модели)

Recommended Posts

ага, вроде разобрался.

dctSize - Размер окна в котором будем находить коэффициенты ДКП

obsSize - Количество значимых коэффициентов.

delta - А вот это сдвиг (в пикселях?)

только я не совсем понял, в дефолтных параметрах размер сдвига 4 на 4, тоесть всего лишь по 4 пикселя раждый раз?

и еще непонятно почему в исходниках #define MAX_DCT_SIZE 32

тоесть максимум окно может быть 32 х 32 пикселя.

Тоесть не получится сканировать например прямоугольным окном чисто по вертикали.

Видимо создатели библиотеки посчитали 32 максимально оптимальным

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Дорогие друзья! Увидел здесь много умных людей, прошу вашей помощи. Очень важно.

Программа распознавание лиц HMM.

Так и не понял как решить эту проблему с функцией cvEstimateObsProb

Пробовал OpenCV 2.3.1, 2.4.3, 2.4.6 - 2.4.8

Visual studio 2010 и 2012.

Подскажите, люди добрые, что делать?

void EHMMObjRecognition::Train( ImgObj &imgObj, EHMMObj &ehmmObj )

{

	const int MAX_ITER = 80;    

	const double STOP_STEP_ITER = 0.01;


	CvImgObsInfo **obsInfoVec;

	IplImage *iplImg;

	int obsVecLen = _noDCTCoeff.width * _noDCTCoeff.height;	

	CvSize _noObs;

	CvEHMM *tmplEhmm = ehmmObj.GetEHMM( ).GetCvEHMM( );

	int numImages = (int)imgObj.GetNoImages( );

    bool trained = false;

    float oldLikelihood = 0; 

    int counter = 0;

	int i;


	assert( _imgWidth != -1 );

	assert( _imgHeight != -1 );


    if( _suppressIntensity )

    {

		//Suppress first DCT coefficient

		obsVecLen--;

    }


	//Create the obsinfo array

    obsInfoVec = new CvImgObsInfo*[ numImages ];

	assert( obsInfoVec != 0 );


	for( i = 0; i < numImages; i++ )

    {	

		iplImg = imgObj.GetGrayScaleImage( i, _imgWidth, _imgHeight );   


		//Get how many DCT transforms we compute

		CountObs( *iplImg->roi, _dctSize, _stepSize, _noObs ); 


		//Create the observation for each of the transforms

        obsInfoVec[ i ] = cvCreateObsInfo( _noObs, obsVecLen );


        if( _suppressIntensity )

        {

            float *observations = new float[ _noObs.height * _noObs.width * ( obsVecLen + 1 ) ];


			cvImgToObs_DCT( iplImg, observations, _dctSize, _noDCTCoeff, _stepSize );


			ExtractDCT( observations, obsInfoVec[ i ]->obs, _noObs.height * _noObs.width, obsVecLen );


			if ( observations )

			{

				delete( observations);

			}

        }

        else

        {

            cvImgToObs_DCT( iplImg, obsInfoVec[ i ]->obs, _dctSize, _noDCTCoeff, _stepSize );

        }


		cvUniformImgSegm( obsInfoVec[ i ], tmplEhmm );


		cvReleaseImage( &iplImg );

    }                                              


    cvInitMixSegm( obsInfoVec, numImages, tmplEhmm );


	//Start the iterative training procedure

	while( ( !trained ) && ( counter < MAX_ITER ) )

    { 

		int j;    

		float likelihood = 0;     


		counter++;


        cvEstimateHMMStateParams( obsInfoVec, numImages, tmplEhmm );


        cvEstimateTransProb( obsInfoVec, numImages, tmplEhmm); 


        for( j = 0; j < numImages; j++ )

        {           



            cvEstimateObsProb( obsInfoVec[ j ], tmplEhmm );                                /// в этой функции

                                                                                           //причем первую итерацию завершает без ошибок

                                                                                           // со второй выдает assertion failed и программа выходит


            likelihood += cvEViterbi( obsInfoVec[ j ], tmplEhmm );                        

        }


        likelihood /= numImages * obsInfoVec[ 0 ]->obs_size;


        cvMixSegmL2( &obsInfoVec[ 0 ], numImages, tmplEhmm );


        trained = ( fabs( likelihood - oldLikelihood ) < STOP_STEP_ITER ); 


        oldLikelihood = likelihood;                   

   }


	//Clear the observations

	for( i = 0; i < numImages; i++ )

	{

		cvReleaseObsInfo( &(obsInfoVec[ i ]) );

	}

	delete []obsInfoVec;


	ehmmObj.GetEHMM( ).SetTrained( trained );

}
что пишет: Assertion failed file: ...opencv\modules\legacy\src\hmm.cpp line: 636 Expression: sizeof(float*)==sizeof(int) Сам кусочек из hmm.cpp
static CvStatus CV_STDCALL icvEstimateObsProb( CvImgObsInfo* obs_info, CvEHMM* hmm )

{

    int i, j;

    int total_states = 0;


    /* check if matrix exist and check current size

       if not sufficient - realloc */

    int status = 0; /* 1 - not allocated, 2 - allocated but small size,

                       3 - size is enough, but distribution is bad, 0 - all ok */


    for( j = 0; j < hmm->num_states; j++ )

    {

       total_states += hmm->u.ehmm[j].num_states;

    }


    if ( hmm->obsProb == NULL )

    {

        /* allocare memory */

        int need_size = ( obs_info->obs_x * obs_info->obs_y * total_states * sizeof(float) +

                          obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f) );


        int* buffer = (int*)cvAlloc( need_size + 3 * sizeof(int) );

        buffer[0] = need_size;

        buffer[1] = obs_info->obs_y;

        buffer[2] = obs_info->obs_x;

        hmm->obsProb = (float**) (buffer + 3);

        status = 3;


    }

    else

    {

        /* check current size */

        int* total= (int*)(((int*)(hmm->obsProb)) - 3);

        int need_size = ( obs_info->obs_x * obs_info->obs_y * total_states * sizeof(float) +

                          obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f/*(float*)*/ ) );



        assert( sizeof(float*) == sizeof(int) );                                                      /////////вот здесь. соответственно возвращает 3



        if ( need_size > (*total) )

        {

            int* buffer = ((int*)(hmm->obsProb)) - 3;

            cvFree( &buffer);

            buffer = (int*)cvAlloc( need_size + 3 * sizeof(int));

            buffer[0] = need_size;

            buffer[1] = obs_info->obs_y;

            buffer[2] = obs_info->obs_x;


            hmm->obsProb = (float**)(buffer + 3);


            status = 3;

        }

    }

    if (!status)

    {

        int* obsx = ((int*)(hmm->obsProb)) - 1;

        int* obsy = ((int*)(hmm->obsProb)) - 2;


        assert( (*obsx > 0) && (*obsy > 0) );


        /* is good distribution? */

        if ( (obs_info->obs_x > (*obsx) ) || (obs_info->obs_y > (*obsy) ) )

            status = 3;

    }


......

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Есть подозрение что это

assert( sizeof(float*) == sizeof(int) );

Возникает на 64 разрядных машинках.

Так как размер указателей зависит от установленной разрядности.

Размер int на windows имеет размер 4 байта.

А размер указателя на память в 32 разрядной версии равен 32, а в 64 разрядной 64.

Вот и выбрасывается исключение.

Можете попробовать соорудить 32 разрядную версию, нужно только установить 32 разрядных OpenCV, и создать 32-разрядный профиль проекта.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Реанимировал распознавалку на марковских моделях.

Правда сыро все пока, больше всего сомнений вызывает выделение памяти, см. мои пометки в файле hmm.cpp строки 28,29.

Распознает вроде все все отлично, но надо допиливать под нормальный C++.

Если у кого руки до этого дойдут, прошу поучаствовать.

HMM.RAR

Как тестить:

1) запустить

2) выбрать папку faces

3) подождать

4) нажимать кнопку, он выдаст фотки из обучающей выборки, лица которое он распознал по невиданной ранее фотке этого лица.

5) нажать кнопку в консоли.

Предъявляемый невиданный индивид задается в файле main.cpp строчках 345,346.

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Из opencv-шного legacy (то, что Вы указали, они не хотели у меня работать из-за assert-a ) и те, что вначале темы для билдера.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Сохранение и загрузка сохраненной модели:

Сохранение:

void HMM_Save( const std::string &fileName, CvEHMM*  _ehmm, int _vecSize )
{
	
	int i = 0;
	int j = 0;
	int m = 0;
	int k = 0;
	vector<int> NumStates;
    assert( _ehmm != 0 );
	FileStorage fs;
	fs.open(fileName, FileStorage::WRITE);
	if(!fs.isOpened())
			return;
	    
    // записываем топологию
    fs << "NumSuperStates" << _ehmm->num_states;
	fs << "NumStates" <<  "[";
	
    for( i = 0; i < _ehmm->num_states; i++ )
    {
        fs << _ehmm->u.ehmm[ i ].num_states;
    }
	fs << "]";
	fs << "NumGaussMixtures" <<  "[";
	for( i = 0; i < _ehmm->num_states; i++ )
        {
          CvEHMM* ehmm = &( _ehmm->u.ehmm[ i ] );

          for( int j = 0; j < ehmm->num_states; j++ )
          {
        	fs << ehmm->u.state[ j ].num_mix ;
          }
        }
	fs << "]";
    
        fs << "VecSize"  << _vecSize;
	
    //Пишем все hmms
    
	CvEHMM* hmm = _ehmm;
        fs << "DataHMM" << "{";
	for( i = 0; i < _ehmm->num_states + 1; i++ )
        {
          if ( hmm->level == 0 )
		{
                   fs << "EmbeddedHMM"+ToString(i) << "{" ;
		}
                else
		{
	         fs << "ExternalHMM" << "{" ;
		}

        fs << "NumStates" << hmm->num_states;
		
        if ( hmm->level == 0 )
        {
            for ( j = 0; j < hmm->num_states; j++)
            {
                      CvEHMMState* state = &( hmm->u.state[ j ] );
		      fs << "State" + ToString(j) <<  "{";
		      fs  << "NumMixes" <<  state->num_mix;
                      float* mu = state->mu;
                      float* inv_var = state->inv_var;
		   for( m = 0; m < state->num_mix; m++)
                   {
                      fs << "Mixture" + ToString(m)<< "{";
		      fs << "Weight" << state->weight[ m ];
		      fs << "Mean" << "[" ; 
		      for ( k = 0; k < _vecSize; k++)
                      {  
                        fs << mu[ 0 ]; 
			mu++;
                      } 
			fs << "]" ; // mean
                	fs << "Inverted_Deviation" << "[";
				                    
                    for ( k = 0; k < _vecSize; k++)
                    {
                        fs << inv_var[ 0 ];
			      inv_var++;
                    }
			fs << "]"; //Inverted_Deviation
                   	fs << "LogVarVal" << state->log_var_val[ m ];
			fs << "}"; //mixture
                }

			   fs << "}";// state
            }
        }

        //
        fs << "TransP" << "[";
	float* prob = hmm->transP;
        for ( int j = 0; j < hmm->num_states; j++)
        {
            for ( int k = 0; k < hmm->num_states; k++)
            {
               fs << *prob;
		       prob++;
            }            
        }
		fs << "]"; //TransP
		fs << "}"; // EmbeddedHMM или ExternalHMM
        hmm = &( _ehmm->u.ehmm[ i ] );
    }
	fs << "}"; //DataHMM
	fs.release();
}

//*****************************************************************************

Загрузка:

bool HMM_Load( const string &fileName, CvEHMM**  _ehmm)
{
	vector<int> states;
	vector<int> GaussMix;
	vector<float> TransP;
	vector<float> Mean;
	string Tmp;
	int NumSuperStates = 0;
	int VecSize = 0;
	
  
	FileStorage fs;
	fs.open(fileName, FileStorage::READ | FileStorage::FORMAT_XML);
	if(!fs.isOpened())
			return false;
   
	
    fs["NumSuperStates"] >> NumSuperStates;
	fs["NumStates"] >> states;
	states.insert(states.begin(),NumSuperStates);
	int size = states.size();
	fs["NumGaussMixtures"] >> GaussMix;
	fs["VecSize"] >> VecSize;
    (*_ehmm) = cvCreate2DHMM( &states[0], &GaussMix[0], VecSize);

    
  
    
	CvEHMM* hmm = *_ehmm;
	FileNode DataHMM = fs["DataHMM"];
	int idx = 0;
        FileNodeIterator it_beg = DataHMM.begin(); 
	FileNodeIterator it_end = DataHMM.end();
	
	for(it_beg; it_beg != it_end; ++it_beg,  ++idx)
	{
		if(idx != 0)
		{
			for(int j=0; j < states[idx]; j++)
			{
			
				
				FileNode node =  (*it_beg)["State"+ToString(j)];//State0
				int count = node.size();
				string name = node.name();
				CvEHMMState* state = &( hmm->u.state[ j ] );
				float* mu = state->mu;
				float* inv_var = state->inv_var;
				
				for( int m = 0; m < state->num_mix; m++)
                                {
					FileNode node_mix = node["Mixture"+ToString(m)];
					Mean.clear();
					state->weight[ m ] = node_mix["Weight"];
					node_mix["Mean"] >> Mean;
					for ( int k = 0; k < VecSize; k++)
                                        {  
                                               (*mu) =  Mean[k]; 
						++mu;
                                        } 
					
					Mean.clear();
					node_mix["Inverted_Deviation"] >> Mean;
					for ( int k = 0; k < VecSize; k++)
                                        {
                                            (*inv_var) = Mean[k];
					     ++inv_var;
                                        }
					state->log_var_val[ m ] = node_mix["LogVarVal"];
				}
			}		
		}
	
		TransP.clear();
		(*it_beg)["TransP"] >> TransP;
		 float* prob = hmm->transP;
		 int counter = 0;
		for ( int j = 0; j < hmm->num_states; j++)
                {
                   for ( int k = 0; k < hmm->num_states; k++)
                   {
                      *prob  = TransP[counter++];
                       prob++;
                   }            
                }
		hmm = &( (*_ehmm)->u.ehmm[ idx] );	
	 }
return true;
}

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Господа, пример с HMM грешит утечками, как чиновник взятками.

Часть вроде поправил, сейчас бьюсь с этим куском:

// Рассчитываем, сколько нужно произвести ДКП (DCT)
        noObs.width = ( img->width - dctSize.width + stepSize.width ) / stepSize.width;
    noObs.height = ( img->height - dctSize.height + stepSize.height ) / stepSize.height;

         info = cvCreateObsInfo( noObs, obsVecLen ); <<--- Большая, жирная утечка. По мегабайту-двум за 1 выполнение.
         assert( info != 0 );

 

И далее:

if( SUPPRESS_INTESITY )
    {
        float *observations = new float[ noObs.height * noObs.width * ( obsVecLen + 1 ) ];
        cvImgToObs_DCT( img, observations, dctSize, noDCTCoeff, stepSize );
        ExtractDCT( observations, info->obs, noObs.height * noObs.width, obsVecLen ); <<---  Маленькая утечка, по 0.5 Мб за проход.
        if ( observations )
        {
            delete( observations);
        }
    }
    else
    {
        cvImgToObs_DCT( img, info->obs, dctSize, noDCTCoeff, stepSize );
    }
    cvEstimateObsProb( info, &tmplEhmm );


Добавил в конце функции распознавания (после return)

cvReleaseObsInfo(&info);
delete info;

Не помогло особо. Есть мысли? Версия опенцв 1я вроде.

-----------------------

P. S. Вроде нашёл как правильно память чистить.

В конце Compute...:

  float temp;
        temp=cvEViterbi( info, &tmplEhmm );
        cvReleaseObsInfo(&info);
        delete info;
    return temp;

Теперь память не утекает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Где-то в коде загрузки, или сохранения модели закрался косячек. 

Сохранять сохраняет, грузит, но потом при ComputeLikeHood вываливается в segfault после 1го сравнения. Причем значение выдает правильное, как при обычном обучении. Сообщение об ошибке в opencv_legacy, а в какой функции - не говорит. Куда копать - пока не знаю. 

Опытным путем установлено, что ошибка возникает тут: cvEstimateObsProb( info, &tmplEhmm ); // Here!!
Однако, если эту строку закомментировать, она всё равно вывалится. Значит, cvEViterbi( info, &tmplEhmm ); работает некорректно. Что-то в загруженной модели не так. 
Накосячить я мог только в одном месте - размере vecSize, который передается HMM_Save при сохранении. Пробовал значения vecSizeM = NO_DCT_COEFF_X * NO_DCT_COEFF_Y - 1; Без -1. Просто от балды. Не работает. 

Кто-нибудь делал загрузку и сохранение модели?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В коде больше не копался, но есть подозрение что память под объект не выделяется (может где new воткнуть надо).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А в новой версии opencv нет реализации hmm?
Нашёл реализации LBPH и SVM, там вообще модель в 3 строки инициализируется, в 2 - сохраняется-загружается. Но HMM показывает самые лучшие результаты. 

Гоняю сейчас на выборке в 300 человек, по 3 фото. И модель строится долговато, минуты 3. Ей бы загрузку-сохранение допилить - будет красота. 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×