Monday, August 10, 2009

Be careful to use cvGetSubRect, cvGetRow and cvGetCol

When you uses these three function or similar function which have cvGetXX part, you must be careful. It return the pointer to return matrix, if you change the value of return matrix, the mother of this submatrix will be changed too. For example:

float a[]={1,2,3,4};
CvMat A=cvMat(2,2,CV_32FC1);
CvMat* B=cvCreateMat(1,2,CV_32FC1);

cvGetRow(&A,B,0);

Of course, here B->data={1,2};
But if we do:

CV_MAT_ELEM(B,float,0,0)=100;

Then you can check the first element of matrix A or array a become 100!!

So Now we understand, these function return the pointer. It gives the first pointer of first row of A to B. But we already give a new space to B, this part of space is not used anymore because the pointer of B is not pointer to "CvMat* B=cvCreateMat(1,2,CV_32FC1);" anymore. We also can not release the B afterwards as it pointer the content of A.
So these three functions are for operation on mother matrix, but not for get content of A.

So the correct way to get a row from A is:
float a[]={1,2,3,4};
CvMat A=cvMat(2,2,CV_32FC1);
CvMat* B=cvCreateMat(1,2,CV_32FC1);

CvMat tmp;

cvGetRow(&A,tmp,0);
cvCopy(&tmp,B);

cvReleaseMat(&B);


Here we go.

2 comments:

Twister said...
This comment has been removed by the author.
Sun said...

Thanks for your information.
Actually I found out, the pointer way just did not work.
e.g.
CvMat *col3rd = cvCreateMat(3, 1, CV_32FC1);
cvGetCol(matLeftUn, col3rd, 2);

the content of col3rd is not the correct value.
Only the way you provided works,
e.g.

CvMat *col3rd = cvCreateMat(3, 1, CV_32FC1);
CvMat tmp2;
cvGetCol(matLeftUn, &tmp2, 2);
cvCopy(&tmp2, col3rd);
Then the content of col3rd contains the correct values.

Any idea why?