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

Mahalanobis

Recommended Posts

Добрый день, я написал свою реализацию расстояния махаланобиса, но проект всё время падает с исключением

Необработанное исключение в "0x751a9617" в "testapp.exe": Исключение Microsoft C++: cv::Exception по адресу 0x0012de30..

ниже код моего метода


double calcMah(const Mat &Xk,const Mat &x)

{

	int rw = Xk.rows;

	int cl = Xk.cols;

	Mat xm(rw,1,CV_64F);


	//calc mean

	for(int r=0; r<rw; r++)

	{

		Mat tmr = Xk.row(r).clone();

		Scalar sc = mean(tmr);

		xm.at<double>(r) = sc.val[0];

	}	


	Mat mv = Mat::ones(rw,cl,CV_64F).mul(xm);

	Mat Xvg=Xk-mv;

	Mat cov =Xvg*Xvg.t();

	Mat icov = cov.inv();

	Mat res = (xm-x)*icov*(xm-x).t();


	return res.at<double>(0);

}

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


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

А падает надо думать на обращении матрицы. Или я ошибаюсь?

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


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

без вызова этого метода проект работает нормально, поэтому я понял, что наверно проблема в самой функции

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


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

так сделайте cout<<"me ok"<< endl; после каждой строчки если с дебагом проблемы. Узнаете на какой ошибка. Можно еще размеры матриц вывести для контроля.

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


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

Mat tmr = Xk.row(r).clone();

Н безопасный метод. У вас ошибка память выделяется, но не освобождается.

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


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

С исключением разобрался вот нормальный код без исключений, только вот сейчас непонятно почему матрица обратная ковариационной у меня всегда получается нулевой..


double calcMah(const Mat &Xk,const Mat &x)

{

	int rw = Xk.rows;

	int cl = Xk.cols;

	Mat xm(rw,1,CV_64F);

	Mat mv(rw,cl,CV_64F);


	//calc mean

	for(int r=0; r<rw; r++)

	{

		Mat tmr = Xk.row(r).clone();

		Scalar sc = mean(tmr);

		xm.at<double>(r) = sc.val[0];

	}		


	for(int i=0; i<rw;i++)

	{

		double tempV = xm.at<double>(i);

		for(int j=0; j<cl;j++)

		{

			mv.at<double>(i,j)=tempV;

		}

	}


	Mat Xvg=Xk-mv;	

	Mat cov =Xvg*Xvg.t();	

	cout<<cov<<endl;

	Mat icov = cov.inv();

	cout<<icov<<endl;

	Mat diff = xm - x;

	cout<<diff<<endl<<diff.rows<<"  |  "<<diff.cols<<endl;

	Mat res = diff.t()*icov*diff;


	return res.at<double>(0);

}

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


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

Может она и есть нулевая. Попробуйте в каком нибудь мат пакете типа MathCad или Maple то же самое сделать. Или давайте матрицу я сделаю у меня Maple установлен.

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


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

я для тестирования использую базу данных изображений, пока просто матрица состоит из 2-х тестовых изображений и одно беру для сравнения или из этого класса или из другого.. приведу код.. я его писал для проверки расстояния махаланобиса (в матрице tempMt из которой и строится ковариационная и обратная к ней матрицы количество строк это размерность изображения вытянутого в вектор, а количество столбцов это количество этих векторов т.е. изображений)


int imSz = 50;// размер изображения для тестирования

	Mat i1 = imread("C:/GTSRB/Final_Train/00000/00000_00026.jpg");//первое изображение из 0-го класса (тренировочное)

	Mat i2 = imread("C:/GTSRB/Final_Train/00000/00005_00029.jpg");//второе изображение из 0-го класса (тренировочное)

	Mat i3 = imread("C:/GTSRB/Final_Train/00016/00006_00028.jpg");//изображение для тестирования

	Mat tst;


	Mat tempMt(imSz*imSz,2,CV_64F);

        //преобразование перового изображения в вектор и запись в tempMt

	{

		Mat nts;

		Mat rts;

		Mat dts;

		Mat nv(imSz*imSz,1,CV_64F);


		cvtColor(i1,nts,CV_BGR2GRAY);

		resize(nts,rts,Size(imSz,imSz));

		rts.convertTo(dts,CV_64F,1.0/255.0);


		int dx=-1;

		for (int r=0;r<imSz;r++ )

		{

			for (int c=0;c<imSz;c++)

			{

				dx++;

				nv.at<double>(dx)=dts.at<double>(r,c);

			}

		}


		for(int p=0; p<imSz*imSz;p++)

		{

			tempMt.at<double>(p,0)=nv.at<double>(p);

		}		

	}

        //преобразование второго изображения в вектор и запись в tempMt

	{

		Mat nts;

		Mat rts;

		Mat dts;

		Mat nv(imSz*imSz,1,CV_64F);


		cvtColor(i2,nts,CV_BGR2GRAY);

		resize(nts,rts,Size(imSz,imSz));

		rts.convertTo(dts,CV_64F,1.0/255.0);


		int dx=-1;

		for (int r=0;r<imSz;r++ )

		{

			for (int c=0;c<imSz;c++)

			{

				dx++;

				nv.at<double>(dx)=dts.at<double>(r,c);

			}

		}


		for(int p=0; p<imSz*imSz;p++)

		{

			tempMt.at<double>(p,1)=nv.at<double>(p);

		}

	}

        //преобразование тестового изображения в вектор, запись в tst

	{

		Mat nts;

		Mat rts;

		Mat dts;

		Mat nv(imSz*imSz,1,CV_64F);


		cvtColor(i3,nts,CV_BGR2GRAY);

		resize(nts,rts,Size(imSz,imSz));

		rts.convertTo(dts,CV_64F,1.0/255.0);


		int dx=-1;

		for (int r=0;r<imSz;r++ )

		{

			for (int c=0;c<imSz;c++)

			{

				dx++;

				nv.at<double>(dx)=dts.at<double>(r,c);

			}

		}


		tst = nv.clone();

	}



	double d = calcMah(tempMt,tst);	

	cout<<d;

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


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

Может быть сначала на меньших размерностях отладить?

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


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

пробовал сперва брать просто придуманные вектора, но тоже ничего хорошего (матрица обратная к ковариационной тоже нулевая)


Mat X = (Mat_<double>(4,2)<<1,3,2,5,3,0,4,7);

Mat x1 = (Mat_<double>(4,1)<<1,2,3,4);

double d = calcMah(X,x1);

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


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

сейчас проверил в маткаде определитель ковариационной матрицы равен 0, что-то как не изменяю матрицу X он всё равно 0

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


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

А что у Вас является координатами точек, между которыми мы меряем расстояние?

Мне кажется размерности векторов должны совпадать, а у среднего должна быть размерность пространства в котором мы работаем. А у Вас что то не то.

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


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

почему не то у меня 4 это размерность пространства т.е. точка в R4 вот всего 2-е точки т.е. первая p1(1,2,3,4); p2(3,5,0,7), ну и точка для тестирования это x1(1,2,3,4)

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


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

а среднее тогда почему по рядам считаете?

              Mat tmr = Xk.row(r).clone();
Scalar sc = mean(tmr);[/code]

Вы же вычисляете среднее между компонент вектора.

У вас Входная матрица 4 ряда 2 столбца, то есть два вертикальных 4 мерных вектора.

Upd:

А, нет я глючусь, все вроде верно со средним.

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


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

ну да вроде бы со средний всё нормально... считается средний вектор его размерность будет 4 строки 1 столбец вроде всё так..

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


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

в маткаде я подобрал точки так что бы обратная матрица к ковариационной была отлична от нуля p1(1,2,3,4);p2(3,5,0,-7); p3(5,-1,11,34);, но у меня в маткаде получился один ответ у программы совсем другой причём если при обращении поставить DECOMP_SVD т.е. Mat icov = cov.inv(DECOMP_SVD); то тоже будет другой ответ... почему что-то не особо ясно.. может ошибка где-то в функции махаланоблиса, которую я написал...

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


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

Легко проверить какой правильный. Перемножьте обращенную и не обращенную, получите единичную.

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


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

вот что у меня получилось

Mat X = (Mat_<double>(4,3)<<1,3,5,22,5,-1,3,20,11,4,-7,34);

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

post-2515-0-84714500-1326965173_thumb.jp

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


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

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

Тут с цифрами пример: http://people.revoledu.com/kardi/tutorial/Similarity/MahalanobisDistance.html

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


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

Спасибо всё действительно работает!)

единственно что-то уж очень долго считает на изображениях

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

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

×