OpenCV - Directly copying matrix multiplication result to a subset of another matrix - c++

I try to directly copying matrix multiplication result to a subset of another matrix:
cv::Mat a,b,c;
//fill matrices a and b and set matrix c to correct size
cv::Mat ab=a*b;
ab.copyTo(c(cv::Rect(0,0,3,3)));
isn' it possible to directly copy the result to matrix c like e.g. (I know this doesn't work):
(a*b).copyTo(c(cv::Rect(0,0,3,3)));
//or
c(cv::Rect(0,0,3,3)).setTo(a*b);
Wouldn't it be more efficient?

Try this:
cv::Mat subC = c(cv::Rect(0,0,3,3));
subC = a*b;
No copying here.
Or more succinctly:
c(cv::Rect(0,0,3,3)) = a*b;

Related

Best way to broadcast Armadillo matrix operations similar to Numpy

Consider the matrices A and B where A is a 5x5 matrix and B is a 1x5 matrix (or a row vector). If I try to do A + B in Numpy, its broadcasting capabilities will implicitly create a 5x5 matrix where each row has the values of B and then do normal matrix addition between those two matrices. This can be written in Armadillo like this;
mat A = randu<mat>(4,5);
mat B = randu<mat>(1,5);
A + B;
But this fails. And I have looked at the documentation and couldn't find a built-in way to do broadcasting. So I want to know the best (fastest) way to do an operation similar to the above.
Of course, I could manually resize the smaller matrix into the size of the larger, and copy the first-row value to each other row using a for loop and use the overloaded + operator in Armadillo. But, I'm hoping that there is a more efficient method to achieve this. Any help would be appreciated!
Expanding on the note from Claes Rolen. Broadcasting for matrices in Armadillo is done using .each_col() and .each_row(). Broadcasting for cubes is done with .each_slice().
mat A(4, 5, fill::randu);
colvec V(4, fill::randu);
rowvec R(5, fill::randu);
mat X = A.each_col() + V; // or A.each_col() += V for in-place operation
mat Y = A.each_row() + R; // or A.each_row() += R for in-place operation
cube C(4, 5, 2, fill::randu);
cube D = C.each_slice() + A; // or C.each_slice() += A for in-place operation

Matrix multiplication optimization

I am performing a series of matrix multiplications with fairly large matrices. To run through all of these operations takes a long time, and I need my program to do this in a large loop. I was wondering if anyone has any ideas to speed this up? I just started using Eigen, so I have very limited knowledge.
I was using ROOT-cern's built in TMatrix class, but the speed for performing the matrix operations is very poor. I set up some diagonal matrices using Eigen with the hope that it handled the multiplication operation in a more optimal way. It may, but I cannot really see the performance difference.
// setup matrices
int size = 8000;
Eigen::MatrixXf a(size*2,size);
// fill matrix a....
Eigen::MatrixXf r(2*size,2*size); // diagonal matrix of row sums of a
// fill matrix r
Eigen::MatrixXf c(size,size); // diagonal matrix of col sums of a
// fill matrix c
// transpose a in place
a.transposeInPlace();
Eigen::MatrixXf c_dia;
c_dia = c.diagonal().asDiagonal();
Eigen::MatrixXf r_dia;
r_dia = r.diagonal().asDiagonal();
// calc car
Eigen::MatrixXf car;
car = c_dia*a*r_dia;
You are doing way too much work here. If you have diagonal matrices, only store the diagonal (and directly use that for products). Once you store a diagonal matrix in a square matrix, the information of the structure is lost to Eigen.
Also, you don't need to store the transposed variant of a, just use a.transpose() inside a product (that is only a minor issue here ...)
// setup matrices
int size = 8000;
Eigen::MatrixXf a(size*2,size);
// fill matrix a....
a.setRandom();
Eigen::VectorXf r = a.rowwise().sum(); // diagonal matrix of row sums of a
Eigen::VectorXf c = a.colwise().sum(); // diagonal matrix of col sums of a
Eigen::MatrixXf car = c.asDiagonal() * a.transpose() * r.asDiagonal();
Finally, of course make sure to compile with optimization enabled, and enable vectorization if available (with gcc or clang compile with -O2 -march=native).

How could I subtract a 1xN eigen matrix from a MxN matrix, like numpy does?

I could not summarize a 1xN matrix from a MxN matrix like I do in numpy.
I create a matrix of np.arange(9).reshape(3,3) with eigen like this:
int buf[9];
for (int i{0}; i < 9; ++i) {
buf[i] = i;
}
m = Map<MatrixXi>(buf, 3,3);
Then I compute mean along row direction:
m2 = m.rowwise().mean();
I would like to broadcast m2 to 3x3 matrix, and subtract it from m, how could I do this?
There is no numpy-like broadcasting available in Eigen, what you can do is reuse the same pattern that you used:
m.colwise() -= m2
(See Eigen tutorial on this)
N.B.: m2 needs to be a vector, not a matrix. Also the more fixed the dimensions, the better the compiler can generate efficient code.
You need to use appropriate types for your values, MatrixXi lacks the vector operations (such as broadcasting). You also seem to have the bad habit of declaring your variables well before you initialise them. Don't.
This should work
std::array<int, 9> buf;
std::iota(buf.begin(), buf.end(), 0);
auto m = Map<Matrix3i>(buf.data());
auto v = m.rowwise().mean();
auto result = m.colwise() - v;
While the .colwise() method already suggested should be preferred in this case, it is actually also possible to broadcast a vector to multiple columns using the replicate method.
m -= m2.replicate<1,3>();
// or
m -= m2.rowwise().replicate<3>();
If 3 is not known at compile time, you can write
m -= m2.rowwise().replicate(m.cols());

Matrix-vector product like multiplication in Eigen

I am currently facing this problem.
I have two matrixes MatrixXf
A:
0.5 0.5 0.5 0.5
0.694496 0.548501 0.680067 0.717111
0.362112 0.596561 0.292028 0.370271
0.56341 0.642395 0.467179 0.598476
and B
0.713072
0.705231
0.772228
0.767898
I want to multiply them like matrix x vector to achive:
0.5*0.713072 0.5*0.713072 0.5*0.713072 0.5*0.713072
0.694496*0.705231 0.548501*0.705231 0.680067*0.705231 0.717111*0.705231
0.362112*0.772228 0.596561*0.772228 0.292028*0.772228 0.370271*0.772228
0.56341*0.767898 0.642395*0.767898 0.467179*0.767898 0.598476*0.767898
Is there an option to do that in Eigen? How can do that a simply way?
http://mathinsight.org/matrix_vector_multiplication
This has been asked so many times, you want a scaling:
MatrixXf A;
VectorXf B;
MatrixXf res = B.asDiagonal() * A;
or using broadcasting:
res = A.array().colwise() * B.array();
In short you want to do an element-wise product between each column of A and vector B.
There are at least two ways of accomplishing this:
iterate over each column of A to do an element-wise product with B (in eigen referred to as coefficient-wise product)
replicate your B vector into a matrix with the same size as A and perform an element-wise product between A and the new matrix obtained from vector B.
Here's a quick and dirty example based on Eigen's cwiseProduct() and replicate() functions:
auto C = A.cwiseProduct( B.replicate<1,4>() );

uchar/float matrices - element by element division and multiplication

I want to divide a matrix cv::Mat src of type CV_8UC1 with a scalar of type float and the result stored in a new matrix srcN of type CV_32FC1:
I'm doing this at the moment:
for(unsigned j=0;j<src.rows;j++)
for(unsigned i=0;i<src.cols;i++)
srcN.at<float>(j,i) = ((int) src.at<uchar>(j,i))/A;
Which is not very fast. I want to do it like this: srcN=src/A; but I don't get the right values in srcN. Is there any way to do that?
Another question: MATLAB (which literally means MATrix LABoratory) is very fast in operations with matrices, how can I make my code as fast as matlab with c++/opencv?