0

GIVEN:

A matrix (N, 3) build from a point cloud, i.e. a vector<Point3d>

std::vector<cv::Point3d> pcVector = ... // from somewhere
cv::Mat                  pcMat = cv::Mat(pcVector).reshape(1);

Thus having pcMat to be something like:

[  0.1, 1.3, 4.5 ]
[  3.1, 1.4, 7.6 ]
   ...
[  1.1, 3.4, 4.1 ]

GOAL:

An efficient method to get a column of ones added to the matrix. That is to receive a matrix like the following from the above.

[  0.1, 1.3, 4.5, 1.0 ]
[  3.1, 1.4, 7.6, 1.0 ]
   ...
[  1.1, 3.4, 4.1, 1.0 ]

CURRENTLY:

cv::Mat  result(N, 4);
cv::Mat  ones = cv::Mat_<double>::ones(N, 1);

cv::hconcat(pcMat, ones, result);

QUESTION:

This seems to be inefficient since a temporary matrix full of ones needs to be created. Are there any tricks to get this done faster?

Frank-Rene Schäfer
  • 3,182
  • 27
  • 51
  • _"seems to be inefficient"_ did you profiled it? – Miki Jun 23 '22 at 08:36
  • You can try to skip allocating the `ones` matrix, and "manually" create the `result` Mat (with the proper size) by copying `pcMat` and adding the column with 1s. However - before doing that you must profile the current code: (1) maybe it is good enough (2) you'll know if the "manual" approach actually works better. – wohlstad Jun 23 '22 at 08:39
  • @Miki it is obvious, that allocating, constructing, merging, and deleting a huge matrix (this is a larger point cloud) causes a significant amount of time. I would assume that a handy matrix function that does that could do much better. But no, I do not have measurements-just reasoning. – Frank-Rene Schäfer Jun 23 '22 at 08:54

1 Answers1

2

Use cv::convertPointsToHomogeneous

The function converts points from Euclidean to homogeneous space by appending 1's to the tuple of point coordinates. That is, each point (x1, x2, ..., xn) is converted to (x1, x2, ..., xn, 1).

// given
std::vector<cv::Point3d> pcVector = ... // from somewhere
cv::Mat                  pcMat = cv::Mat(pcVector).reshape(1);

// I did not run this
cv::Mat dst;
cv::convertPointsToHomogeneous(pcMat, dst); // pcVector oughta work too

As always, these things will accept both Nx1 K-channel Mats as well as NxK 1-channel Mats. The result seems to always be Nx1 (K+1)-channel though.

And... you can imagine what convertPointsFromHomogeneous would do.

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
  • This function actually perfectly seems to do what I wanted. However, it produces a `cv::Mat` of type `CV_F64C4` instead of `CV_F64C1` from `vector`. Thus, the result cannot be used in any matrix multiplication and `convertTo()` does not support removing channels. – Frank-Rene Schäfer Jun 23 '22 at 12:12
  • 1
    if you use `cv::transform`, you can keep that shape. `transform` does matrix-vector multiplication, also for lists of vectors (Nx1 K-channel matrices, also NxK 1-ch). if you really need to, you can `Mat::reshape(1)` to convert from Nx1 K-channel (CV_64FC4) to NxK 1-channel (CV_64FC1) https://docs.opencv.org/4.x/d3/d63/classcv_1_1Mat.html#a4eb96e3251417fa88b78e2abd6cfd7d8 – Christoph Rackwitz Jun 23 '22 at 12:43