1

I would like to know how to pass a matrix as an optional argument in a function. If the argument is not given, then it is set to be an identity matrix.

If I do something like

Mat function(const Mat &I, Mat &matrix=Mat::eye(2, 3, CV_32F))
{
    /// some code

    return matrix;
}

then I get the following error:

error: could not convert ‘cv::Mat::eye(int, int, int)(3, 5)’ from ‘cv::MatExpr’ to ‘cv::Mat&’

Thanks in advance for any suggestions.

f10w
  • 1,524
  • 4
  • 24
  • 39
  • do you have to pass by reference? Why do you want to pass by reference? – Micka Sep 11 '14 at 10:46
  • No I do not. I just want to pass the matrix in argument, modify it, and then return it. – f10w Sep 11 '14 at 10:53
  • so just removing the `&` should work I guess. – Micka Sep 11 '14 at 10:54
  • Unfortunately not. I got the following error: `error: default argument given for parameter 3 of ‘cv::Mat tMatch_lk(const cv::Mat&, const cv::Mat&, cv::Mat)’`. I'm on 64 bits Ubuntu 14.04. – f10w Sep 11 '14 at 10:59
  • did you add the default value in both, header and cpp file? – Micka Sep 11 '14 at 12:38

3 Answers3

4

You are getting this problem because C++ does not allow a temporary (the default value in this case) to be bound to non-const reference. You have three (at least) choices:

Mat function(const Mat &I, const Mat & matrix = Mat::eye(2, 3, CV_32F))

or

Mat function(const Mat &I, Mat const & matrix = Mat::eye(2, 3, CV_32F))

or

Mat function(const Mat &I, Mat matrix = Mat::eye(2, 3, CV_32F)) 

Or as berak said, you could make the default an empty Mat, and test for it with Mat::empty():

Mat function(const Mat &I, Mat & matrix = Mat()) 
Community
  • 1
  • 1
Bull
  • 11,771
  • 9
  • 42
  • 53
  • For the first two, is it possible to modify `matrix` and then return it? I tried the third but get the following error: `error: default argument given for parameter 3 of ‘cv::Mat tMatch_lk(const cv::Mat&, const cv::Mat&, cv::Mat)’` I'm on 64 bits Ubuntu 14.04. – f10w Sep 11 '14 at 10:59
  • For the first two, the Mat is const so you can't simply change the Mat itself, but you can change the image data pointed to by matrix.data, e.g. `float * p = (float*) matrix.ptr(0); p[1] = 55.0f;`. And of course you can return matrix. For the third case I had to call it like this : `Mat m = function(Mat::zeros(2, 2, CV_32F), (const Mat) Mat::eye(4, 4, CV_32F));` (VS2012) If you don't really need the references, I would get rid of them. – Bull Sep 11 '14 at 13:53
  • Thanks. The third solution works if I define `function()` BEFORE `main()`. Otherwise it does not work (i.e. if it is declared before, but defined after, the function `main()`). But I don't understand why. – f10w Sep 11 '14 at 15:22
  • Strange, makes no difference with VS2012 – Bull Sep 11 '14 at 15:46
  • 4
    Hmm, isn't `Mat function(const Mat &I, Mat & matrix = Mat())` doing exactly what the first sentence of this answer says you can't? – Dan Mašek Jun 28 '17 at 13:06
  • I've used the third version successfully in visual c++ in the past. Now I'm trying to port the project to linux and I'm getting an error with g++ `cv::Mat & outImage_ = cv::Mat()` as a parameter in a static member function: `error: could not convert ‘cv::Mat()’ from ‘cv::Mat’ to ‘cv::Mat&’` Any idea what kind of problem there is and how to solve? `static std::vector detect(cv::Mat _inImage, float minTubeAreaRatio, cv::Mat & outImage_ = cv::Mat());` – Micka Oct 23 '17 at 11:38
2

I think passing by reference doesnt make much sense here.

One reason to pass by reference would be to use the parameter as a return value (so modify the input), but then a default value doesn't make much sense.

The other reason to pass by reference might be some performance improvement, to not copy the whole data. This isn't critical für cv::Mat since it's only a header and the data field is copied by reference/pointer anyways. If you have to call that function very often, then you might have a performance improvement by not copying the header, but in this case you don't want to have a default value which creates a new cv::Mat all the time.

So my solution to your problem would be to pass by value:

cv::Mat function(cv::Mat matrix = cv::Mat::eye(2,3, CV_32F))
{
    return matrix;
}

int main()
{
    std::cout << function() << "\n\n" ;

    std::cout << function(cv::Mat::zeros(2,3, CV_32F)) << std::endl;

    return 0;
}

gives me this terminal output as wanted/expected:

[1, 0, 0;
  0, 1, 0]

[0, 0, 0;
  0, 0, 0]
Micka
  • 19,585
  • 4
  • 56
  • 74
  • Thanks. I figured it out. I declare that function before the main function, and define it after (see the code below), so it does not work. But I don't understand why it does not work :\ `#include... Mat function(Mat matrix = Mat::eye(2,3, CV_32F)); int main() {...} Mat function(Mat matrix = Mat::eye(2,3, CV_32F)) {...}` – f10w Sep 11 '14 at 15:17
  • Micka: since @B... posted his answer 2 hours earlier, I think the credits should go to him first. But I appreciate your answer. Thanks again. +1. – f10w Sep 11 '14 at 15:27
  • thats ok for me. just wanted to explain why passing by reference doesnt make much sense here from my point of view and wanted to try that one for myself, because you mentioned in your comment that it gave you compile errors. – Micka Sep 11 '14 at 15:29
  • Thanks. As I've explained above, instead of defining the function before the main function, I defined it AFTER the main, and then declared it in the header. That caused the error. But I have no idea why. – f10w Sep 11 '14 at 15:32
-2

You could try with Boosts' Optional (http://www.boost.org/doc/libs/1_47_0/libs/optional/doc/html/index.html), or write such a template by yourself - it is very useful.

You could also pass the matrix via pointer instead of reference. Then if pointer is set to 0 or nullptr, you would initialize it to whatever you would like to.

pmatyszok
  • 142
  • 5