Jump to content
Compvision.ru
Smorodov

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

Recommended Posts

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

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

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

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

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

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

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

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

Программа распознавание лиц 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;

    }


......

Share this post


Link to post
Share on other sites

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

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

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

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

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

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

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

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

Share this post


Link to post
Share on other sites

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

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

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

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

HMM.RAR

Как тестить:

1) запустить

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

3) подождать

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

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

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

  • Like 1

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

Сохранение:

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

Share this post


Link to post
Share on other sites

Господа, пример с 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;

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

Share this post


Link to post
Share on other sites

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

Сохранять сохраняет, грузит, но потом при 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. Просто от балды. Не работает. 

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×