0

I am trying to use pointer with cv::Mat, but I don't quite understand it.

When I try this:

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

using namespace cv;
using namespace std;

int main()
{
    Mat src = imread("image.png");
    Mat img;
    Mat temp;

    img = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0));
    temp = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0));

    temp = img(Range(10, 20), Range(40, 60));
    temp.setTo(255);

    imshow("img", img);
    waitKey();
    return 0;
}

It works and there is no problem. However, when I change it to:

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

using namespace cv;
using namespace std;

int main()
{
    Mat src = imread("image.png");
    Mat* img;
    Mat* temp;

    *img = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0));
    *temp = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0));

    temp = img(Range(10, 20), Range(40, 60));
    temp.setTo(255);

    imshow("img", *img);
    waitKey();
    return 0;
}

I get this error:

expression preceding parentheses of apparent call must have (pointer-to-) function type

at

temp = img(Range(10, 20), Range(40, 60));

and the error:

expression must have class type

at

temp.setTo(255);

What is the general rule in dealing with Mats as pointers to speed up the code?

I know for example, in function arguments we use & for input Mats and * for output Mats. But is there a general rule how to define and use Mats inside the functions?

Please tell me if there are other things wrong with this code, since I am a beginner. Thank you!

Hadi GhahremanNezhad
  • 2,377
  • 5
  • 29
  • 58

1 Answers1

3

In the example you posted there is no benefit to be gained from using pointers. In your example with pointers there are a number of problems.

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

using namespace cv;
using namespace std;

int main()
{
    Mat src = imread("image.png");
    Mat* img; // Uninitialized pointer; points to random memory
    Mat* temp; // Uninitialized pointer; points to random memory

    // Undefined behavior: dereferencing an uninitialized pointer
    // You are basically trying to treat some random piece of memory
    // as a cv::Mat and trying to assign another cv::Mat to it.
    *img = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0)); 
    *temp = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0));

    // Syntax error: img has type Mat*; you could call the
    // Mat Mat::operator()( Range _rowRange, Range _colRange ) const
    // Like this:
    // *temp = img->operator()(Range(10, 20), Range(40, 60));
    // or like this:
    // *temp = (*img)(Range(10, 20), Range(40, 60));
    // that would work if img and temp were to point to valid cv::Mats
    temp = img(Range(10, 20), Range(40, 60));
    // Syntax error temp has type Mat*
    //  to access a pointers members use -> instead of .
    temp.setTo(255);

    imshow("img", *img);
    waitKey();
    return 0;
}

In general copying a cv::Mat is a low cost operation since it does not create a copy of the whole buffer but instead just increases the ref count and copies some information how to interpret that buffer. On typical hardware you can expect that to take on the order of a few dozen nanoseconds at most. Simple image processing operations can easily take a million times as long.

There seldom is a reason to have a pointer to a cv::Mat. If you switch to a pointer do so because it makes more sense, not in an effort to increase performance. Passing your mats by (const) reference instead of by value may still be right default choice though.

One use case of having a cv::Mat pointer might be an optional out parameter:

 void mayBeNull(cv::Mat* matPointer = nullptr)
 {
    if(matPointer!=nullptr)
    {
       // assign something to *matPointer
    }
    else
    {
       // do not use matPointer
       // the caller does not care about our outparam
    }
 }
Stefan v.K.
  • 356
  • 2
  • 8
  • 1
    Thank you for the very helpful answer. Just for the last point, do you mean it's better to use `Mat*` in the function arguments if the `Mat` is an output image? – Hadi GhahremanNezhad Nov 07 '19 at 17:57
  • 3
    In general if you have an output parameter in C++ you can choose between making it a reference or a pointer. Syntax aside the difference is that a reference can not be null but a pointer can. So if you want to make your out parameter optional it usually makes sense to make it a pointer. – Stefan v.K. Nov 07 '19 at 18:19