hjweide
hjweide

Reputation: 12533

OpenCV cv::Mat to short* (avoiding memcpy)

I have a C++ function that is to be called from someone else's C# application. As input my function is given an array of signed short integers, the dimensions of the image it represents, and memory allocated for the returning data, namely another array of signed short integers. This would represent my function's header:

my_function (short* input, int height, int width, short* output)

Inside my function I create a cv::Mat from input, like this:

cv::Mat mat_in = cv::Mat (height, width, CV_16S, input);

This mat_in is then converted to CV_32F and processed by OpenCV's cv::bilateralFilter. After it returns cv::Mat mat_out, I convert the data back to CV_16S (bilateralFilter only accepts CV_8U and CV_32F). Now I need to convert this cv::Mat mat_out back to an array of short integers so that it may be returned to the calling function. This is my code:

my_function (short* input, int height, int width, short* output)
{
    Mat mat_in_16S = Mat (height, width, CV_16S, input);

    Mat mat_in_32F = Mat (height, width, CV_32F);
    Mat mat_out_CV_32F = Mat (height, width, CV_32F);

    mat_in_16S.convertTo (mat_in_32F, CV_32F);

    bilateralFilter (mat_in_32F, mat_out_32F, 5, 160, 2);
    Mat mat_out_16S = Mat (mat_in_16S.size(), mat_in_16S.type());
    mat_out_32F.convertTo (mat_out_16S, CV_16S);

    return 0;
}

Obviously, somewhere there at the end I need to get the data that is in mat_out_16S into output. My first try was to return a reference:

output = &mat_out_16S.at<short>(0,0);

but of course I realised that this was a silly idea, as mat_out_16S goes out of scope as soon as the function returns, leaving output pointing at emptiness. Currently my best attempt is as follows (from this question):

memcpy ((short*)output, (short*)mat_out_16S.data, height*width*sizeof(short));

Now I would like to know, is there a better way? It feels kind of inefficient to copy all this data, but I don't see what else I can do. I can't return a cv::Mat unfortunately. If there is no better way, is my current memcpy method safe at least? My data are all 2-byte signed short integers, so I don't think there should be issues with padding, but I don't want to run into any unpleasant surprises.

Upvotes: 2

Views: 2510

Answers (1)

Alexey
Alexey

Reputation: 5978

You can use this constructor for your mat_out_16S:

Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)

So your function will be:

my_function (short* input, int height, int width, short* output)
{
    Mat mat_in_16S = Mat (height, width, CV_16S, input);

    Mat mat_in_32F = Mat (height, width, CV_32F);
    Mat mat_out_CV_32F = Mat (height, width, CV_32F);

    mat_in_16S.convertTo (mat_in_32F, CV_32F);

    bilateralFilter (mat_in_32F, mat_out_32F, 5, 160, 2);
    Mat mat_out_16S = Mat (mat_in_16S.size(), mat_in_16S.type(), output);
    mat_out_32F.convertTo (mat_out_16S, CV_16S);

    return 0;
}

Upvotes: 1

Related Questions