3

I'm using OpenCV 3.2.

Let's suppose I have a 3 x 1 Mat:

cv::Mat foo = (cv::Mat_<float>(3,1) << 0, 1, 2);

Now I want to concatenate a single value to foo, and then having a resulting 4 x 1 Mat.

A simple solution would be:

cv::Mat bar = (cv::Mat_<float>(4,1) << foo.at<float>(0,0),
                                       foo.at<float>(1,0),
                                       foo.at<float>(2,0),
                                       3);

But this solution overfits to the problem dimensions. Of course, I can generalize it by looping all the values of an n x 1 Mat, resulting in an n+1 x 1.

What I'm looking for is a smarter solution that takes advantage of OpenCV syntax, and directly returns the concatenation of a single-column Mat and a single value.

Santiago Gil
  • 1,292
  • 7
  • 21
  • 52

1 Answers1

3

You're in luck. cv::Mat provides member function push_back which

adds elements to the bottom of the matrix

Furthermore,

The methods add one or more elements to the bottom of the matrix. They emulate the corresponding method of the STL vector class. ...

Since your Mat has a single column, you can just simply add scalar values, you just have to make sure the type matches the data type of the Mat. In you case you can add floats directly, but anything else you need to cast to float explicitly before adding.

If you had a Mat with a single row, and wanted to add a column, it would be a little more complicated. You're need to use reshape before and after the push_back. However, to quote the documentation

No data is copied. That is, this is an O(1) operation.

If you need to do this often, then it's trivial to wrap it in an inline function.

Example

#include <iostream>
#include <opencv2/opencv.hpp>

int main()
{
    // Adding rows

    cv::Mat foo = (cv::Mat_<float>(3, 1) << 0, 1, 2);
    std::cout << foo << "\n";

    foo.push_back(3.0f);
    std::cout << foo << "\n";

    foo.push_back(static_cast<float>(4)); // Need to make sure the type matches!
    std::cout << foo << "\n";

    // -----

    // Adding columns

    cv::Mat bar = (cv::Mat_<float>(1, 3) << 0, 1, 2);
    std::cout << bar << "\n";

    // push_back needs to add a full row so reshapes are needed (but cheap)
    bar = bar.reshape(1, bar.cols);
    bar.push_back(3.0f);
    bar = bar.reshape(bar.rows);
    std::cout << bar << "\n";

    return 0;
}

Console Output

[0;
 1;
 2]
[0;
 1;
 2;
 3]
[0;
 1;
 2;
 3;
 4]
[0, 1, 2]
[0, 1, 2, 3]
Dan Mašek
  • 17,852
  • 6
  • 57
  • 85