function outputs different matrix

Pages: 12
Hi

It is getting more and more annoying, everytime i progress the next hurdle is just bigger.

the problem is i want to calculate inverse of a matrix but using .inv gives a matrix full of -1.#QNAN values so i decided to write one my self

a function which returns the inverse matrix but something strange happens.

when i debug through the function code it works well and check the matrix that will be returned and the elements are correct.

when the function is called and output matrix is resulted. the element of the matrix is different.

matrix = inversemat(matrx)

inside function, invmat= 3 1 2, 3 5 1, 8 1 2

outside the function matrix = -9.1249e+61 wtf.

here is the code

1
2
3
4
5
6
7
8
int main()
{
	double matrx[3][3]={{1,2,3},{0,1,4},{5,6,0}};
	Mat matrx1(3,3,CV_64F,matrx);
	Mat inmat;
	inmat=inversemat(matrx1);

}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Mat inversemat(Mat matrx)
{
	double determ;
	
	determ = (matrx.at<double>(0,0)*((matrx.at<double>(1,1)*matrx.at<double>(2,2))-(matrx.at<double>(1,2)*matrx.at<double>(2,1))))+(matrx.at<double>(0,1)*((matrx.at<double>(1,0)*matrx.at<double>(2,2))-(matrx.at<double>(2,0)*matrx.at<double>(1,2))))+(matrx.at<double>(0,2)*((matrx.at<double>(1,0)*matrx.at<double>(2,1))-(matrx.at<double>(1,1)*matrx.at<double>(2,0))));
	Mat mt=matrx.t();
	double m11,m12,m13,m21,m22,m23,m31,m32,m33;
	
	cout<<"transposed"<<endl;
	cout<<mt.at<double>(0,0)<<" "<<mt.at<double>(0,1)<<" "<<mt.at<double>(0,2)<<endl;
	cout<<mt.at<double>(1,0)<<" "<<mt.at<double>(1,1)<<" "<<mt.at<double>(1,2)<<endl;
	cout<<mt.at<double>(2,0)<<" "<<mt.at<double>(2,1)<<" "<<mt.at<double>(2,2)<<endl;
	
	m11=(mt.at<double>(1,1)*mt.at<double>(2,2))-(mt.at<double>(2,1)*mt.at<double>(1,2));
	m12=(mt.at<double>(1,0)*mt.at<double>(2,2))-(mt.at<double>(2,0)*mt.at<double>(1,2));
	m13=(mt.at<double>(1,0)*mt.at<double>(2,1))-(mt.at<double>(2,0)*mt.at<double>(1,1));
	m21=(mt.at<double>(0,1)*mt.at<double>(2,2))-(mt.at<double>(2,1)*mt.at<double>(0,2));
	m22=(mt.at<double>(0,0)*mt.at<double>(2,2))-(mt.at<double>(2,0)*mt.at<double>(0,2));
	m23=(mt.at<double>(0,0)*mt.at<double>(2,1))-(mt.at<double>(2,0)*mt.at<double>(0,1));
	m31=(mt.at<double>(0,1)*mt.at<double>(1,2))-(mt.at<double>(1,1)*mt.at<double>(0,2));
	m32=(mt.at<double>(0,0)*mt.at<double>(1,2))-(mt.at<double>(1,0)*mt.at<double>(0,2));
	m33=(mt.at<double>(0,0)*mt.at<double>(1,1))-(mt.at<double>(1,0)*mt.at<double>(0,1));

	double imat[3][3]={{m11,-m12,m13},{-m21,m22,-m23},{m31,-m32,m33}};
	Mat invmat(3,3,CV_64F,imat);
	

	return invmat;
}


invmat elements are correct
as for inmat the elements are toooo small -9.212412e+61

what is going on, when the matrix is returned.

thanks
You're returning the matrix by value from inversemat(). This means that you're making a copy of the matrix - or possibly more than one copy, as temporary copies might also be created depending on the compiler and the optimisation options you're using.

My guess would be that there's a problem with the copy constructor of Mat. There's no way we can tell, though, since you haven't shown us the definition of Mat.
You're using this constructor:
(7) Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)


which has this comment about the data parameter:

data – Pointer to the user data. Matrix constructors that take data and step parameters do not allocate matrix data. Instead, they just initialize the matrix header that points to the specified data, i.e. no data is copied. This operation is very efficient and can be used to process external data using OpenCV functions. The external data is not automatically deallocated, user should take care of it.


Since the array you initialize your Mat with goes out of scope when the function returns, the Mat no longer refers to a valid object.
Last edited on
so how do i solve this issue in terms of changing my code?

im still new to opencv and that constructor is all new to me.

i think i would need a pointer maybe?
Last edited on
im still new to opencv and that constructor is all new to me.

I've never used opencv, but I can read the docs...

Changing line 28 of inversemat to return invmat.clone(); should work.
Last edited on
so you must know a lot about c++ and how constructors and destructors work.

that is something i am weak at, there is soo much info in the docs i don't know where to start looking.

any good books to learn on understanding docs and constructors and destructors

EDIT:I just tried it and it worked.

thanks, something i can add to my knowledge base for future use.
What book are you using to learn C++ now? Any tutorial book on C++ that covers classes will cover constructors and destructors.

In this case, it's not so much about some esoteric knowledge about constructors in general. It's about understanding memory management, and about knowing about how the openCV class you're using works.

For memory management, again, and decent C++ tutorial book should cover it.

Other than that, it's about reading the openCV documentation for the particular classes and methods you're using.
Putting all my code together to loop through the entire code it takes about 2 seconds and it does this for each pixel in the image.

and this loops through all the pixels in the image which is 640*480 pixels.

total of 614400 seconds which is long.

my code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
int main()
{
	//create matrix to store image
	Mat image;
	Mat covmat,icovar;
	Scalar meanmat;
	//double sample = 1120;
	Mat mask = Mat::zeros(480, 640, CV_8UC1);	//create matrix same size as image which is 480 by 640 based on the webcam capture
	//intitialize capture
	Vec3b pixel;
	double distance = 250.773;
	double mdist=0;
	VideoCapture cap;
	cap.open(-1);
	//create widnow to show image
	namedWindow("original",1);
	namedWindow("mask",1);

	while(1){
		//copy webcam stream to image
		cap>>image;
		//print image to screen
		for(int i = 1; i < image.rows;i++)
		{
			for(int j=1;j<image.cols;j++)
			{
				meanmat=meanpixel(image);
				covmat=covarmatrixcal(image,meanmat);
				pixel= image.at<Vec3b>(i-1,j-1);	
				
				//own made inv matrix function
				icovar=inversemat(covmat);
				mdist=mahadistance(icovar,meanmat,pixel);
				if(mdist>distance)
					mask.at<uchar>(i-1,j-1)=255;
				else
					mask.at<uchar>(i-1,j-1)=0;
			}
		}
	
		imshow("original",image);
		imshow("mask",mask);
		
		//delay 33ms
		waitKey(33);
	}
}


so waiting at imshow would take 614400 seconds.

this is soooo long.

most of the inbuilt functions result in unhandled exception error so had to make my own functions as simple as possible.

any way of reducing the execution time.
thanks
Last edited on
Just a quick suggestion: everything that you don't need to compute inside a loop move it outside. I think you can move lines 27 and 28, and maybe 32. It seems to me like you repeat those commands a lot of times, and you might not need to.
I can place outside the for loop but not outside while loop as the image changes as it is captured from webcam i will see how it goes.

thanks

EDIT:
Its a bit better now, it takes about 6 seconds to execute one while loop till imshow.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
while(1){
		//copy webcam stream to image
		cap>>image;
		//print image to screen
                meanmat=meanpixel(image);
		covmat=covarmatrixcal(image,meanmat);
                icovar=inversemat(covmat);
		for(int i = 1; i < image.rows;i++)
		{
			for(int j=1;j<image.cols;j++)
			{
				pixel= image.at<Vec3b>(i-1,j-1);	
				
				//own made inv matrix function
				mdist=mahadistance(icovar,meanmat,pixel);
				if(mdist>distance)
					mask.at<uchar>(i-1,j-1)=255;
				else
					mask.at<uchar>(i-1,j-1)=0;
			}
		}
	
		imshow("original",image);
		imshow("mask",mask);


any other ways i can slow it down? ideally 1 image per second.
do comments slow a program down i.e. if a code is heavily commented.

inverse and calcovariance and mahadistance functions already exist but using them gives unhandled exception so i had to write my own programs and the processing power would be quicker as it is only comprised of calculations.

thanks
Last edited on
Check which of the functions take takes the most time. Look into parallel computing (OpenMP). Also look at what compiler flags are you using, see if you can optimize that, i.e. if you are using g++ compile it with -O3 flag
is there a place in visual studios 2010 where i can see which compiler flags its using and change it and how do you find out which one is th.

i will look into OpenMP.
thnaks
is there a place in visual studios 2010 where i can see which compiler flags its using and change it and how do you find out which one is th.

Open the project properties and look at the C/C++ section. There are lots of subsections allowing you to specify all sorts of compiler options, as well as a Command Line section which allows you to see the actual command line that will be used to compile.
The following functions take around 2-3 seconds i don't know why, its straight forward calculations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Scalar meanpixel(Mat matrx)
{
	Scalar meanpix;

	for(int i=1;i<=matrx.rows;i++)
	{
		for(int j=1;j<=matrx.cols;j++)
		{
			meanpix[0]=meanpix[0]+double(matrx.at<Vec3b>(i-1,j-1)[0]);
			meanpix[1]=meanpix[1]+double(matrx.at<Vec3b>(i-1,j-1)[1]);
			meanpix[2]=meanpix[2]+double(matrx.at<Vec3b>(i-1,j-1)[2]);
		}
	}
	meanpix[0]=floor((meanpix[0]/(matrx.rows*matrx.cols))+0.5);
	meanpix[1]=floor((meanpix[1]/(matrx.rows*matrx.cols))+0.5);
	meanpix[2]=floor((meanpix[2]/(matrx.rows*matrx.cols))+0.5);
	return meanpix;
}

Mat covarmatrixcal(Mat matrx1, Scalar meanscal)
{

	double rr=0,rg=0,rb=0,gr=0,gg=0,gb=0,br=0,bg=0,bb=0;
	int k=0;
	k=(matrx1.rows*matrx1.cols);
	for(int i = 1; i <= matrx1.rows;i++)
	{
		for(int j=1;j<=matrx1.cols;j++)
		{
			rr=rr+((double(matrx1.at<Vec3b>(i-1,j-1)[0])-meanscal[0])*(double(matrx1.at<Vec3b>(i-1,j-1)[0])-meanscal[0]));
			rg=rg+((double(matrx1.at<Vec3b>(i-1,j-1)[0])-meanscal[0])*(double(matrx1.at<Vec3b>(i-1,j-1)[1])-meanscal[1]));
			rb=rb+((double(matrx1.at<Vec3b>(i-1,j-1)[0])-meanscal[0])*(double(matrx1.at<Vec3b>(i-1,j-1)[2])-meanscal[2]));
			gg=gg+((double(matrx1.at<Vec3b>(i-1,j-1)[1])-meanscal[1])*(double(matrx1.at<Vec3b>(i-1,j-1)[1])-meanscal[1]));
			gb=gb+((double(matrx1.at<Vec3b>(i-1,j-1)[1])-meanscal[1])*(double(matrx1.at<Vec3b>(i-1,j-1)[2])-meanscal[2]));
			bb=bb+((double(matrx1.at<Vec3b>(i-1,j-1)[2])-meanscal[2])*(double(matrx1.at<Vec3b>(i-1,j-1)[2])-meanscal[2]));
		}
	}
	rr=rr/(k-1);
	rg=rg/(k-1);
	rb=rb/(k-1);
	gr=rg;
	gg=gg/(k-1);
	gb=gb/(k-1);
	br=rb;
	bg=gb;
	bb=bb/(k-1);

	double m[3][3]={{rr,rg,rb},{gr,gg,gb},{br,bg,bb}};

	Mat covmatrix(3,3,CV_64F,m);
	return covmatrix.clone();

}


so do you think this can be shortened so it executes quicker.

thanks for the help so far
Here are a few suggestions:
1. the for loops should be from 0, i.e. for(int i = 0; i < matrx1.rows;i++) so you will have matrx1.at<Vec3b>(i,j) instead of matrx1.at<Vec3b>(i-1,j-1). This will cut out a lot of subtraction operations
2. in the inner for loops, assign first matrx1.at<Vec3b>(i,j) to a temporary variable, and use that. Just in case the look-up of element (i,j) is slow
3. if you always call both functions, consider joining them so you go only once through the double loop. This might cut down a serious chunk of time.
1.didn't know it performed calculations i thought it would just go, nice to know.

2.i don't understand what you mean, store first matrx1.at<Vec3b>(i,j) to temp to use. so something like this.

1
2
3
4
5
6
7
8
9
Vec3b temp;
for(int j=1;j<=matrx1.cols;j++)
	{
                         if(j==1)
                         {
                                  temp=matrx1.at<Vec3b>(i,j);
                         }
                        rr=temp+(temp[0]-meanscal[0])*(temp[0]-meanscal[0]);    //then this won't sum as it needs to sum all the red minus the mean red pixel.
		}

do you mean instead of rr=rr+ you want it rr=temp + the rest because covar element consists of summing.

3.oh yeah thats a good idea never thought of that they both loop through pixels.

since i can't return multiple variables i would need to return them by reference so would referencing a matrix like below work

1
2
3
4
5
6
7
Function definition
void covarmatrixcal(Mat* matrx1, Scalar* meanscal

calling function
Mat matrx;
Scalar meanvec;
covarmatrixcal(&matrx, &mean)


nice one
thanks
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
	
for(int i = 0; i < matrx1.rows;i++)
  {
    for(int j=0;j<matrx1.cols;j++)
      {
          Vec3b temp=matrx1.at<Vec3b>(i,j);
          rr=rr+((double(temp[0])-meanscal[0])*(double(temp[0])-meanscal[0]));
          rg=rg+((double(temp[0])-meanscal[0])*(double(temp[1])-meanscal[1]));
          rb=rb+((doubletemp[0])-meanscal[0])*(double(temp[2])-meanscal[2]));
          
AND SO ON

      }
}


For return, you can return a tuple http://www.cplusplus.com/reference/tuple/tuple/

Anyway, look into make it run in parallel
Last edited on
that parallel thing is quite interesting, definitely to learn more, but what i have read is that using openMP i can make all the things work in parralel like rr,rg,rb... all be assigned at the same time which is cool.

first i will need to succesfully install openmp sucessfully for visual studio, do you know any good tutorial.

when using openmp.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for(int i = 0; i < matrx1.rows;i++)
  {
    for(int j=0;j<matrx1.cols;j++)
      {
           #pragma opm parallel
           {
                  rr=rr+((double(temp[0])-meanscal[0])*(double(temp[0])-meanscal[0]));
                  rg=rg+((double(temp[0])-meanscal[0])*(double(temp[1])-meanscal[1]));
                  rb=rb+((double(temp[0])-meanscal[0])*(double(temp[2])-meanscal[2]));
          
                   AND SO ON
             }
      }
}


something like that?
everything in the pragma omp parallel braces will run in parallel.

nice
Last edited on
Hi

I can actually remove the mean and covariance function from the while loop, i will only need to calculate it once for one image only thats it.

but definitely would like to learn the parallel execution stuff in case i have to write other codes which will slow it down.

thanks

Pages: 12