vector and mats

This question boils down to this throwing an exception:

<Mat L = m * v>

The reason is the although m is a 3 x 3 matrix (camera intrinsics) it cannot be multiplied by v which is type vector: std::vector<cv::Point3d>v. I find vector very useful because all I have to do is pass the vector to a function then I can unpack it by indices. Unfortunately I can't say the same for matrices unless I am missing a way to pass multiple matrices to a function without listing all of them in the function header.

I could try this:

<Mat V(v)>

and unpack each matrix in the same way by converting each indices from Point3d to a matrix. But is there any more efficient solution?

Thank you.
Last edited on
lets pretend we don't know what a matrix is to you.
Yes, we know what it means, but does your class not support [] or [][] type access? If not, you need a new matrix class :)

you can define a multiply of matrix to point3d with an operator overload or function.

you can make a variadic function that can accept N parameters where N is unknown, but I hate them, they are ugly to me. Sometimes its what must be done.

but lets start with your matrix class ... tell us more..
you can define a multiply of matrix to point3d with an operator overload or function


I am very interested in how to do this.

I don't have a matrix class, let know what it is (uh oh). I do know that the above expression:
Mat L = m * v doesn't work with Point3d and Matrices when multiplied.
More specifically, this below doesn't work, is not elegant.

1
2
3
4
5
6
7
8
9
10
11
void normalize(cv::Mat &M, std::vector < cv::Point3d>&img_pts_vec3, std::vector < cv::Point3d>&pNorm)
{	
	Mat result = M * img_pts_vec3[0];
	pNorm.push_back(Point3d(result));
	result = M * img_pts_vec3[1];;
	pNorm.push_back(Point3d(result));
	result = M * img_pts_vec3[2];
	pNorm.push_back(Point3d(result));
	result = M * img_pts_vec3[3];
	pNorm.push_back(Point3d(result));
}


each * is an error
Severity Code Description Project File Line Suppression State
Error C2678 binary '*': no operator found which takes a left-hand operand of type 'cv::Mat' (or there is no acceptable conversion) c:\users\clang\desktop\working folder\rayplaneapp\rayplaneapp\rayplaeapp.cpp 121
the easy way out is just to write a stand alone function.

Mat multiply_mat_x_p3d(Mat &m, point3d &p3d)
{
//code to do the multiply.
}

otherwise I think you have to inherit Mat into your own class and extend it that way, which is a lot of work just to get a multiply operator and all your mats would need to be converted to the new type (you can set up a cast for it), or any that you wanted to do this math on. Even if you have the source for Mat, you wouldn't want to modify it, as a new version would lose your changes if they released a new version of the library. Its possible to do that, but it is not ideal.

it won't look like A*B with a stand alone function, but if you can live with
Mat L = multiply_mat_x_p3d(m, v);
instead, you are good to go.
if you want to pursue an inheritance approach, we can do that. It only seems worth it to me if you have a number of items to create, eg + - * / and more ... maybe that [] operator...?
Last edited on
I started down several overly complicated paths and circled back to a fairly simple one.

Consider this overly simple example. It probably has some inefficiencies to work through to avoid copying data an extra time or the like, but the general idea may be enough for you. I freely admit to not doing a lot of this sort of thing (trying to wrap and extend a library). I tend to use what they gave me directly instead. So one of our gurus can probably make this 1000% better.

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


struct mat //represents someone else's class that you can't modify
{
	vector<double> d{1.0,2.0,3.0};	
};

struct p3d //represents someone else's class that you can't modify
{
	vector<double> d{2.0,3.0,4.0};	
};

struct m //you build something to enable the * syntax.
{	 
      mat *pmat;      
	  m(mat &in) {pmat = &in;}			
	  operator mat(){return *pmat;} //my small example assumes pmat is valid here...
	
	m operator *(p3d &p)
	{	
	  mat tmp = *pmat;
      for(int i = 0; i < 3; i++)
        tmp.d[i] *= p.d[i];	//not a matrix multiply, just a quick example
	  return tmp;
	}	

};


int main()
{
   mat m1;
   p3d p1;
   
   mat res = (m)m1*p1; //all you need now is a simple cast to multiply a mat * a point 3d.  it may be inefficiently copying data -- its a crude quick example. 
   for(int i = 0; i < 3; i++)
    cout << res.d[i] << endl; 
}



apart from the extra overhead (construction of m object), its pretty much the same as making the multiply function I described, but this shovels it into an operator so you get the 'better syntax'. If you can make it *= (destructive) you can avoid the copy of mat to mat as well.
If you are doing a ton of them, or need extreme performance, ask and I will look at improvements.

if you don't mind the object being disposable and used only as above in the casting, this should only create ONE extra mat object ever, and avoid an extra m creation as well, so it should be decent.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct m
{	 
      static mat staticmat; //keep one working space mat variable forever. 
      mat *pmat;      //the mat object that this class wraps
	  m(mat &in) {pmat = &in;}//ctor 			
	  operator mat(){return *pmat;} //allow cast m to mat
	
	m operator *(p3d &p) //multiply operator
	{	
	  staticmat = *pmat; //the real mat would have things that need to be copied/set correctly, hopefully a simple = does the trick
      for(int i = 0; i < 3; i++)
       staticmat.d[i] *= p.d[i];	//not a matrix multiply, just a quick example
      pmat = &staticmat; //this object is disposable, just to tap the multiply. if you use this class for anything else, this is wrong. 
	  return *this; 
	}
	
}; mat m:: staticmat;
Last edited on

I am new to C++, so I must keep everything as simple as possible, I have not yet used templates, so my matrix is a double.
Skipping using a matrix class or structure, and sticking to vectors of double, I can simulate the original request (roughly) viz:
Mat L = m * v
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

#include<vector>
#include<iostream>
#include<string>
using namespace std;

#define MATRIX 	vector<vector<double>>
#define VECTOR  vector<double>


VECTOR operator *(MATRIX m1,VECTOR m2)
{
int rows=m1.size(),r,k;
	if (m1.size() != m2.size()) {printf(" uncompatible indices  nothing done \n ");return m2;}
	vector<double>ans;
	double rxc;
	ans.resize(rows);
	rows=rows-1;
	for(r=0;r<=rows;r++)
	{
		rxc=0;
		for(k=0;k<=rows;k++)
		{
			rxc=rxc+m1[r][k]*m2[k];
		}
	ans[r]=rxc;	
	}
	return ans;		
	
}

MATRIX operator *( MATRIX m1,MATRIX m2)
{
	//overload  to be done if required (mat*mat) with print function below
}



void print(VECTOR v)
{
	int n=v.size(),i;
	string sp;
	for(i=0;i<n;i++)
	{
		if(v[i]>=0) sp="+"; else sp="";
		cout<<sp<<v[i]<<endl;
	}
	cout<<endl;	
}



int main()

{
	
	MATRIX unit
    {
        {1,0,0,0},
        {0,1,0,0},
        {0,0,1,0},
        {0,0,0,1}
    };	
	
	
	
	
	MATRIX d
    {
        {-150, -2,-3,9},
        {-4, 5, 6,2},
        {7, 8.5,-9,8},
        {2, 0, -3,8}
    };
 
    
     VECTOR r
 {
 	{1.1,2.2,3.3,4.4}
 };

//==============//
VECTOR answer=d*r;
print(answer);

print(unit*r);

cout <<"  "<<endl;
cout <<"Press return to end . . ."<<endl; 
cin.get();	 

}


 

There may be some Matrix operations in a library somewhere.
The C++ coders proper will know.



technologist wrote:
I don't have a matrix class

1
2
void normalize( cv::Mat &M,
 ...

If you don't have matrix class, then what is that cv::Mat?
Is it the https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html that mbozzi pointed to?

At end of that page:
Note
Matrix Expressions and arithmetic see MatExpr

The cv::Mat seems to have multiplication for Mat and Scalar. Point3d is neither of those.

However, there is probably some way around it, as is hinted in: https://stackoverflow.com/questions/18523894/conversion-of-3x1-or-1x3-cvmat-to-cvpoint3d
Last edited on
Keskiverto wrote:
The cv::Mat seems to have multiplication for Mat and Scalar. Point3d is neither of those
Jonnin wrote
the easy way out is just to write a stand alone function.it won't look like A*B with a stand alone function, but if you can live with


Per above this didn't work, compiler error:

1
2
3
4
5
void multiply_mat_x_p3d(Mat &m, Point3d &p3d)
{   
	Mat result = m.inv() * p3d;
	//code to do the multiply.
}


But this did with converting Point3d type to mat:
1
2
3
4
5
void multiply_mat_x_p3d(Mat &m, Point3d &p3d)
{   
	Mat result = m.inv() * Mat(p3d);
	//code to do the multiply.
}

"Reindexing" isn't hard. This works:
 
pNorm.push_back(Point3d(result.at<double>(0,0), result.at<double>(1,0), result.at<double>(2,0))); //RLQ vertex 


At the top:
1
2
std::vector<cv::Point3d>pNorm;
std::vector<cv::Point3d>result;

A lot of great answers here to pick through. This is pretty lightweight as far as performance though.
Last edited on
Topic archived. No new replies allowed.