marcman - 7 months ago 56

C++ Question

Is there a way to computer the outer product (**z** * transpose(**z**) for some column vector **z**) using the

`cv::Mat`

I've checked the documentation and there's no built in function. But I'm getting exceptions trying to use the standard matrix multiplication expression (*) with a vector of type

`cv::Mat`

Here's the (pseudo)code:

`cv::Mat tmp = cv::Mat::zeros(9, 1, CV_32SC1)`

cv::Mat outerProduct = tmp * tmp.t();

The outer product calculation gives exceptions. (Yes I have actual values in the tmp matrix in my actual code, but this description gives more info about the data type being used)

Ideally, the

`cv::Mat outerProduct`

I could do it using the scaling multiplication property of

`cv::Mat`

`tmp`

`cv::Mat outerProduct = cv::repeat(tmp, 1, 9);`

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

{

outerProduct.col(i) *= tmp.at<int>(i, 0);

}

...but it would be nice to have a better way if there is one.

Answer

Note that while my answer is correct, @kaanoner's answer gives better performance.

They sneak these methods in where you least expect. This one is in Operations on Arrays and it's called mulTransposed.

```
cv::Mat tmp = (Mat_<double>(9,1) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
cv::Mat outerProduct;
mulTransposed(tmp, outerProduct, false);
```

The third parameter is `aTa`

. If it's true, the method calculates a^{T}a. If it's false, it calculates aa^{T}.

Output is:

```
tmp =
[1; 2; 3; 4; 5; 6; 7; 8; 9]
outerProduct =
[1, 2, 3, 4, 5, 6, 7, 8, 9;
2, 4, 6, 8, 10, 12, 14, 16, 18;
3, 6, 9, 12, 15, 18, 21, 24, 27;
4, 8, 12, 16, 20, 24, 28, 32, 36;
5, 10, 15, 20, 25, 30, 35, 40, 45;
6, 12, 18, 24, 30, 36, 42, 48, 54;
7, 14, 21, 28, 35, 42, 49, 56, 63;
8, 16, 24, 32, 40, 48, 56, 64, 72;
9, 18, 27, 36, 45, 54, 63, 72, 81]
```

Looking through the source code, it appears that `CV_32S`

is not supported by `mulTransposed`

. Here are the source and destination types they specify:

```
(stype == CV_8U && dtype == CV_32F)
(stype == CV_8U && dtype == CV_64F)
(stype == CV_16U && dtype == CV_32F)
(stype == CV_16U && dtype == CV_64F)
(stype == CV_16S && dtype == CV_32F)
(stype == CV_16S && dtype == CV_64F)
(stype == CV_32F && dtype == CV_32F)
(stype == CV_32F && dtype == CV_64F)
(stype == CV_64F && dtype == CV_64F)
```

As this implies, the destination type is always a float type. Even when I specify a dtype of `CV_16S`

, I get a matrix that's `CV_32F`

.